<commit_before>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

package service

import (
	"encoding/json"
	"fmt"
)

// DataClient represents the RPC connection to the Data service.
type DataClient struct {
	*Client
}

// NewDataClient returns a new Data Client.
func NewDataClient() *DataClient {
	var service_ DataClient
	service_.Client = new(Client)
	return &service_
}

// GetNode returns the given node or nil if it does not exist.
func (s *DataClient) GetNode(site, path string) (*NodeInfo, error) {
	if s.Error != nil {
		return nil, s.Error
	}
	args := struct{ Site, Path string }{site, path}
	var reply []byte
	err := s.RPCClient.Call("Data.GetNode", args, &reply)
	if err != nil {
		return nil, fmt.Errorf("service: GetNode error: %v", err)
	}
	node := &NodeInfo{}
	err = json.Unmarshal(reply, node)
	if err != nil {
		return nil, fmt.Errorf("service: Could not decode node: %v", err)
	}
	return node, nil
}

// GetChildren returns the children of the given node.
func (s *DataClient) GetChildren(site, path string) ([]*NodeInfo, error) {
	if s.Error != nil {
		return nil, s.Error
	}
	args := struct{ Site, Path string }{site, path}
	var reply [][]byte
	err := s.RPCClient.Call("Data.GetChildren", args, &reply)
	if err != nil {
		return nil, fmt.Errorf("service: GetChildren error: %v", err)
	}
	nodes := make([]*NodeInfo, 0, len(reply))
	for _, entry := range reply {
		node := &NodeInfo{}
		err = json.Unmarshal(entry, node)
		if err != nil {
			return nil, fmt.Errorf("service: Could not decode node: %v", err)
		}
		nodes = append(nodes, node)
	}
	return nodes, nil
}

// GetNodeData requests data from some node.
//
// Returns a nil slice and nil error if the data does not exist.
func (s *DataClient) GetNodeData(site, path, file string) ([]byte, error) {
	if s.Error != nil {
		return nil, s.Error
	}
	type GetNodeDataArgs struct {
	}
	args := struct{ Site, Path, File string }{
		site, path, file}
	var reply []byte
	err := s.RPCClient.Call("Data.GetNodeData", &args, &reply)
	if err != nil {
		return nil, fmt.Errorf("service: GetNodeData error:", err)
	}
	return reply, nil
}

// WriteNodeData writes data for some node.
func (s *DataClient) WriteNodeData(site, path, file, content string) error {
	if s.Error != nil {
		return nil
	}
	args := struct {
		Site, Path, File, Content string
	}{
		site, path, file, content}
	if err := s.RPCClient.Call("Data.WriteNodeData", &args, new(int)); err != nil {
		return fmt.Errorf("service: WriteNodeData error: %v", err)
	}
	return nil
}

// UpdateNode saves changes to given node.
func (s *DataClient) UpdateNode(site string, node_ NodeInfo) error {
	if s.Error != nil {
		return nil
	}
	args := struct {
		Site string
		Node NodeInfo
	}{
		site, node_}
	if err := s.RPCClient.Call("Data.UpdateNode", &args, new(int)); err != nil {
		return fmt.Errorf("service: UpdateNode error: %v", err)
	}
	return nil
}

// RemoveNode recursively removes the given site's node.
func (s *DataClient) RemoveNode(site string, node string) error {
	if s.Error != nil {
		return nil
	}
	args := struct {
		Site, Node string
	}{site, node}
	if err := s.RPCClient.Call("Data.RemoveNode", args, new(int)); err != nil {
		return fmt.Errorf("service: RemoveNode error: %v", err)
	}
	return nil
}
<commit_msg>Add FillFields method.<commit_after>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

package service

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// DataClient represents the RPC connection to the Data service.
type DataClient struct {
	*Client
}

// NewDataClient returns a new Data Client.
func NewDataClient() *DataClient {
	var service_ DataClient
	service_.Client = new(Client)
	return &service_
}

// GetNode returns the given node or nil if it does not exist.
func (s *DataClient) GetNode(site, path string) (*NodeInfo, error) {
	if s.Error != nil {
		return nil, s.Error
	}
	args := struct{ Site, Path string }{site, path}
	var reply []byte
	err := s.RPCClient.Call("Data.GetNode", args, &reply)
	if err != nil {
		return nil, fmt.Errorf("service: GetNode error: %v", err)
	}
	node := &NodeInfo{}
	err = json.Unmarshal(reply, node)
	if err != nil {
		return nil, fmt.Errorf("service: Could not decode node: %v", err)
	}
	return node, nil
}

// FillFields loads the fields of the given nodes into target.
//
// If only one node is given, target must be a pointer to a struct.
// If more than one node is given, the target must be an initialized
// slice of structs.
//
// After loading the fields into the target, the node will be assigned
// to the target's (possibly embedded) NodeInfo field.
func (s *DataClient) FillFields(target interface{}, site string, nodes ...*NodeInfo) error {
	if s.Error != nil {
		return s.Error
	}
	targetType := reflect.TypeOf(target)
	targetValue := reflect.ValueOf(target)
	switch len(nodes) {
	case 0:
		return nil
	case 1:
		if targetType.Kind() != reflect.Ptr ||
			targetType.Elem().Kind() != reflect.Struct {
			return fmt.Errorf("service: Target must be a pointer to a struct")
		}
		fields, err := s.GetNodeData(site, nodes[0].Path, "fields.json")
		if err != nil {
			return fmt.Errorf("Could not get node fields: %v", err)
		}
		err = json.Unmarshal(fields, target)
		if err != nil {
			return fmt.Errorf("Could not decode fields for %q: %v", nodes[0].Path, err)
		}
		info := targetValue.Elem().FieldByName("NodeInfo")
		info.Set(reflect.ValueOf(nodes[0]))
		return nil
	default:
		if targetType.Kind() != reflect.Ptr ||
			targetType.Elem().Kind() != reflect.Slice ||
			targetValue.Elem().IsNil() {
			return fmt.Errorf("service: Target must be a pointer to a non-nil slice")
		}
		for _, node := range nodes {
			singleTarget := reflect.New(targetType.Elem().Elem())
			if err := s.FillFields(singleTarget.Interface(), site, node); err != nil {
				return err
			}
			targetValue.Elem().Set(
				reflect.Append(targetValue.Elem(), singleTarget.Elem()))
		}
		return nil
	}
}

// GetChildren returns the children of the given node.
func (s *DataClient) GetChildren(site, path string) ([]*NodeInfo, error) {
	if s.Error != nil {
		return nil, s.Error
	}
	args := struct{ Site, Path string }{site, path}
	var reply [][]byte
	err := s.RPCClient.Call("Data.GetChildren", args, &reply)
	if err != nil {
		return nil, fmt.Errorf("service: GetChildren error: %v", err)
	}
	nodes := make([]*NodeInfo, 0, len(reply))
	for _, entry := range reply {
		node := &NodeInfo{}
		err = json.Unmarshal(entry, node)
		if err != nil {
			return nil, fmt.Errorf("service: Could not decode node: %v", err)
		}
		nodes = append(nodes, node)
	}
	return nodes, nil
}

// GetNodeData requests data from some node.
//
// Returns a nil slice and nil error if the data does not exist.
func (s *DataClient) GetNodeData(site, path, file string) ([]byte, error) {
	if s.Error != nil {
		return nil, s.Error
	}
	type GetNodeDataArgs struct {
	}
	args := struct{ Site, Path, File string }{
		site, path, file}
	var reply []byte
	err := s.RPCClient.Call("Data.GetNodeData", &args, &reply)
	if err != nil {
		return nil, fmt.Errorf("service: GetNodeData error:", err)
	}
	return reply, nil
}

// WriteNodeData writes data for some node.
func (s *DataClient) WriteNodeData(site, path, file, content string) error {
	if s.Error != nil {
		return nil
	}
	args := struct {
		Site, Path, File, Content string
	}{
		site, path, file, content}
	if err := s.RPCClient.Call("Data.WriteNodeData", &args, new(int)); err != nil {
		return fmt.Errorf("service: WriteNodeData error: %v", err)
	}
	return nil
}

// UpdateNode saves changes to given node.
func (s *DataClient) UpdateNode(site string, node_ NodeInfo) error {
	if s.Error != nil {
		return nil
	}
	args := struct {
		Site string
		Node NodeInfo
	}{
		site, node_}
	if err := s.RPCClient.Call("Data.UpdateNode", &args, new(int)); err != nil {
		return fmt.Errorf("service: UpdateNode error: %v", err)
	}
	return nil
}

// RemoveNode recursively removes the given site's node.
func (s *DataClient) RemoveNode(site string, node string) error {
	if s.Error != nil {
		return nil
	}
	args := struct {
		Site, Node string
	}{site, node}
	if err := s.RPCClient.Call("Data.RemoveNode", args, new(int)); err != nil {
		return fmt.Errorf("service: RemoveNode error: %v", err)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package syntax

//go:generate stringer -type token -linecomment -trimprefix _

type token uint32

// The list of all possible tokens.
const (
	illegalTok token = iota

	_EOF
	_Newl
	_Lit
	_LitWord
	_LitRedir

	sglQuote // '
	dblQuote // "
	bckQuote // `

	and    // &
	andAnd // &&
	orOr   // ||
	or     // |
	orAnd  // |&

	dollar       // $
	dollSglQuote // $'
	dollDblQuote // $"
	dollBrace    // ${
	dollBrack    // $[
	dollParen    // $(
	dollDblParen // $((
	leftBrack    // [
	dblLeftBrack // [[
	leftParen    // (
	dblLeftParen // ((

	rightBrace    // }
	rightBrack    // ]
	rightParen    // )
	dblRightParen // ))
	semicolon     // ;

	dblSemicolon // ;;
	semiAnd      // ;&
	dblSemiAnd   // ;;&
	semiOr       // ;|

	exclMark // !
	addAdd   // ++
	subSub   // --
	star     // *
	power    // **
	equal    // ==
	nequal   // !=
	lequal   // <=
	gequal   // >=

	addAssgn // +=
	subAssgn // -=
	mulAssgn // *=
	quoAssgn // /=
	remAssgn // %=
	andAssgn // &=
	orAssgn  // |=
	xorAssgn // ^=
	shlAssgn // <<=
	shrAssgn // >>=

	rdrOut   // >
	appOut   // >>
	rdrIn    // <
	rdrInOut // <>
	dplIn    // <&
	dplOut   // >&
	clbOut   // >|
	hdoc     // <<
	dashHdoc // <<-
	wordHdoc // <<<
	rdrAll   // &>
	appAll   // &>>

	cmdIn  // <(
	cmdOut // >(

	plus     // +
	colPlus  // :+
	minus    // -
	colMinus // :-
	quest    // ?
	colQuest // :?
	assgn    // =
	colAssgn // :=
	perc     // %
	dblPerc  // %%
	hash     // #
	dblHash  // ##
	caret    // ^
	dblCaret // ^^
	comma    // ,
	dblComma // ,,
	at       // @
	slash    // /
	dblSlash // //
	colon    // :

	tsExists  // -e
	tsRegFile // -f
	tsDirect  // -d
	tsCharSp  // -c
	tsBlckSp  // -b
	tsNmPipe  // -p
	tsSocket  // -S
	tsSmbLink // -L
	tsSticky  // -k
	tsGIDSet  // -g
	tsUIDSet  // -u
	tsGrpOwn  // -G
	tsUsrOwn  // -O
	tsModif   // -N
	tsRead    // -r
	tsWrite   // -w
	tsExec    // -x
	tsNoEmpty // -s
	tsFdTerm  // -t
	tsEmpStr  // -z
	tsNempStr // -n
	tsOptSet  // -o
	tsVarSet  // -v
	tsRefVar  // -R

	tsReMatch // =~
	tsNewer   // -nt
	tsOlder   // -ot
	tsDevIno  // -ef
	tsEql     // -eq
	tsNeq     // -ne
	tsLeq     // -le
	tsGeq     // -ge
	tsLss     // -lt
	tsGtr     // -gt

	globQuest // ?(
	globStar  // *(
	globPlus  // +(
	globAt    // @(
	globExcl  // !(
)

type RedirOperator token

const (
	RdrOut = RedirOperator(rdrOut) + iota
	AppOut
	RdrIn
	RdrInOut
	DplIn
	DplOut
	ClbOut
	Hdoc
	DashHdoc
	WordHdoc
	RdrAll
	AppAll
)

type ProcOperator token

const (
	CmdIn = ProcOperator(cmdIn) + iota
	CmdOut
)

type GlobOperator token

const (
	GlobQuest = GlobOperator(globQuest) + iota
	GlobStar
	GlobPlus
	GlobAt
	GlobExcl
)

type BinCmdOperator token

const (
	AndStmt = BinCmdOperator(andAnd) + iota
	OrStmt
	Pipe
	PipeAll
)

type CaseOperator token

const (
	Break = CaseOperator(dblSemicolon) + iota
	Fallthrough
	Resume
	ResumeKorn
)

type ParNamesOperator token

const (
	NamesPrefix      = ParNamesOperator(star)
	NamesPrefixWords = ParNamesOperator(at)
)

type ParExpOperator token

const (
	SubstPlus = ParExpOperator(plus) + iota
	SubstColPlus
	SubstMinus
	SubstColMinus
	SubstQuest
	SubstColQuest
	SubstAssgn
	SubstColAssgn
	RemSmallSuffix
	RemLargeSuffix
	RemSmallPrefix
	RemLargePrefix
	UpperFirst
	UpperAll
	LowerFirst
	LowerAll
	OtherParamOps
)

type UnAritOperator token

const (
	Not = UnAritOperator(exclMark) + iota
	Inc
	Dec
	Plus  = UnAritOperator(plus)
	Minus = UnAritOperator(minus)
)

type BinAritOperator token

const (
	Add = BinAritOperator(plus)
	Sub = BinAritOperator(minus)
	Mul = BinAritOperator(star)
	Quo = BinAritOperator(slash)
	Rem = BinAritOperator(perc)
	Pow = BinAritOperator(power)
	Eql = BinAritOperator(equal)
	Gtr = BinAritOperator(rdrOut)
	Lss = BinAritOperator(rdrIn)
	Neq = BinAritOperator(nequal)
	Leq = BinAritOperator(lequal)
	Geq = BinAritOperator(gequal)
	And = BinAritOperator(and)
	Or  = BinAritOperator(or)
	Xor = BinAritOperator(caret)
	Shr = BinAritOperator(appOut)
	Shl = BinAritOperator(hdoc)

	AndArit = BinAritOperator(andAnd)
	OrArit  = BinAritOperator(orOr)
	Comma   = BinAritOperator(comma)
	Quest   = BinAritOperator(quest)
	Colon   = BinAritOperator(colon)

	Assgn    = BinAritOperator(assgn)
	AddAssgn = BinAritOperator(addAssgn)
	SubAssgn = BinAritOperator(subAssgn)
	MulAssgn = BinAritOperator(mulAssgn)
	QuoAssgn = BinAritOperator(quoAssgn)
	RemAssgn = BinAritOperator(remAssgn)
	AndAssgn = BinAritOperator(andAssgn)
	OrAssgn  = BinAritOperator(orAssgn)
	XorAssgn = BinAritOperator(xorAssgn)
	ShlAssgn = BinAritOperator(shlAssgn)
	ShrAssgn = BinAritOperator(shrAssgn)
)

type UnTestOperator token

const (
	TsExists = UnTestOperator(tsExists) + iota
	TsRegFile
	TsDirect
	TsCharSp
	TsBlckSp
	TsNmPipe
	TsSocket
	TsSmbLink
	TsSticky
	TsGIDSet
	TsUIDSet
	TsGrpOwn
	TsUsrOwn
	TsModif
	TsRead
	TsWrite
	TsExec
	TsNoEmpty
	TsFdTerm
	TsEmpStr
	TsNempStr
	TsOptSet
	TsVarSet
	TsRefVar
	TsNot = UnTestOperator(exclMark)
)

type BinTestOperator token

const (
	TsReMatch = BinTestOperator(tsReMatch) + iota
	TsNewer
	TsOlder
	TsDevIno
	TsEql
	TsNeq
	TsLeq
	TsGeq
	TsLss
	TsGtr
	AndTest   = BinTestOperator(andAnd)
	OrTest    = BinTestOperator(orOr)
	TsMatch   = BinTestOperator(equal)
	TsNoMatch = BinTestOperator(nequal)
	TsBefore  = BinTestOperator(rdrIn)
	TsAfter   = BinTestOperator(rdrOut)
)

func (o RedirOperator) String() string    { return token(o).String() }
func (o ProcOperator) String() string     { return token(o).String() }
func (o GlobOperator) String() string     { return token(o).String() }
func (o BinCmdOperator) String() string   { return token(o).String() }
func (o CaseOperator) String() string     { return token(o).String() }
func (o ParNamesOperator) String() string { return token(o).String() }
func (o ParExpOperator) String() string   { return token(o).String() }
func (o UnAritOperator) String() string   { return token(o).String() }
func (o BinAritOperator) String() string  { return token(o).String() }
func (o UnTestOperator) String() string   { return token(o).String() }
func (o BinTestOperator) String() string  { return token(o).String() }
<commit_msg>syntax: add inline comments to all operator values<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package syntax

//go:generate stringer -type token -linecomment -trimprefix _

type token uint32

// The list of all possible tokens.
const (
	illegalTok token = iota

	_EOF
	_Newl
	_Lit
	_LitWord
	_LitRedir

	sglQuote // '
	dblQuote // "
	bckQuote // `

	and    // &
	andAnd // &&
	orOr   // ||
	or     // |
	orAnd  // |&

	dollar       // $
	dollSglQuote // $'
	dollDblQuote // $"
	dollBrace    // ${
	dollBrack    // $[
	dollParen    // $(
	dollDblParen // $((
	leftBrack    // [
	dblLeftBrack // [[
	leftParen    // (
	dblLeftParen // ((

	rightBrace    // }
	rightBrack    // ]
	rightParen    // )
	dblRightParen // ))
	semicolon     // ;

	dblSemicolon // ;;
	semiAnd      // ;&
	dblSemiAnd   // ;;&
	semiOr       // ;|

	exclMark // !
	addAdd   // ++
	subSub   // --
	star     // *
	power    // **
	equal    // ==
	nequal   // !=
	lequal   // <=
	gequal   // >=

	addAssgn // +=
	subAssgn // -=
	mulAssgn // *=
	quoAssgn // /=
	remAssgn // %=
	andAssgn // &=
	orAssgn  // |=
	xorAssgn // ^=
	shlAssgn // <<=
	shrAssgn // >>=

	rdrOut   // >
	appOut   // >>
	rdrIn    // <
	rdrInOut // <>
	dplIn    // <&
	dplOut   // >&
	clbOut   // >|
	hdoc     // <<
	dashHdoc // <<-
	wordHdoc // <<<
	rdrAll   // &>
	appAll   // &>>

	cmdIn  // <(
	cmdOut // >(

	plus     // +
	colPlus  // :+
	minus    // -
	colMinus // :-
	quest    // ?
	colQuest // :?
	assgn    // =
	colAssgn // :=
	perc     // %
	dblPerc  // %%
	hash     // #
	dblHash  // ##
	caret    // ^
	dblCaret // ^^
	comma    // ,
	dblComma // ,,
	at       // @
	slash    // /
	dblSlash // //
	colon    // :

	tsExists  // -e
	tsRegFile // -f
	tsDirect  // -d
	tsCharSp  // -c
	tsBlckSp  // -b
	tsNmPipe  // -p
	tsSocket  // -S
	tsSmbLink // -L
	tsSticky  // -k
	tsGIDSet  // -g
	tsUIDSet  // -u
	tsGrpOwn  // -G
	tsUsrOwn  // -O
	tsModif   // -N
	tsRead    // -r
	tsWrite   // -w
	tsExec    // -x
	tsNoEmpty // -s
	tsFdTerm  // -t
	tsEmpStr  // -z
	tsNempStr // -n
	tsOptSet  // -o
	tsVarSet  // -v
	tsRefVar  // -R

	tsReMatch // =~
	tsNewer   // -nt
	tsOlder   // -ot
	tsDevIno  // -ef
	tsEql     // -eq
	tsNeq     // -ne
	tsLeq     // -le
	tsGeq     // -ge
	tsLss     // -lt
	tsGtr     // -gt

	globQuest // ?(
	globStar  // *(
	globPlus  // +(
	globAt    // @(
	globExcl  // !(
)

type RedirOperator token

const (
	RdrOut   = RedirOperator(rdrOut) + iota // >
	AppOut                                  // >>
	RdrIn                                   // <
	RdrInOut                                // <>
	DplIn                                   // <&
	DplOut                                  // >&
	ClbOut                                  // >|
	Hdoc                                    // <<
	DashHdoc                                // <<-
	WordHdoc                                // <<<
	RdrAll                                  // &>
	AppAll                                  // &>>
)

type ProcOperator token

const (
	CmdIn  = ProcOperator(cmdIn) + iota // <(
	CmdOut                              // >(
)

type GlobOperator token

const (
	GlobQuest = GlobOperator(globQuest) + iota // ?(
	GlobStar                                   // *(
	GlobPlus                                   // +(
	GlobAt                                     // @(
	GlobExcl                                   // !(
)

type BinCmdOperator token

const (
	AndStmt = BinCmdOperator(andAnd) + iota // &&
	OrStmt                                  // ||
	Pipe                                    // |
	PipeAll                                 // |&
)

type CaseOperator token

const (
	Break       = CaseOperator(dblSemicolon) + iota // ;;
	Fallthrough                                     // ;&
	Resume                                          // ;;&
	ResumeKorn                                      // ;|
)

type ParNamesOperator token

const (
	NamesPrefix      = ParNamesOperator(star) // *
	NamesPrefixWords = ParNamesOperator(at)   // @
)

type ParExpOperator token

const (
	SubstPlus      = ParExpOperator(plus) + iota // +
	SubstColPlus                                 // :+
	SubstMinus                                   // -
	SubstColMinus                                // :-
	SubstQuest                                   // ?
	SubstColQuest                                // :?
	SubstAssgn                                   // =
	SubstColAssgn                                // :=
	RemSmallSuffix                               // %
	RemLargeSuffix                               // %%
	RemSmallPrefix                               // #
	RemLargePrefix                               // ##
	UpperFirst                                   // ^
	UpperAll                                     // ^^
	LowerFirst                                   // ,
	LowerAll                                     // ,,
	OtherParamOps                                // @
)

type UnAritOperator token

const (
	Not   = UnAritOperator(exclMark) + iota // !
	Inc                                     // ++
	Dec                                     // --
	Plus  = UnAritOperator(plus)            // +
	Minus = UnAritOperator(minus)           // -
)

type BinAritOperator token

const (
	Add = BinAritOperator(plus)   // +
	Sub = BinAritOperator(minus)  // -
	Mul = BinAritOperator(star)   // *
	Quo = BinAritOperator(slash)  // /
	Rem = BinAritOperator(perc)   // %
	Pow = BinAritOperator(power)  // **
	Eql = BinAritOperator(equal)  // ==
	Gtr = BinAritOperator(rdrOut) // >
	Lss = BinAritOperator(rdrIn)  // <
	Neq = BinAritOperator(nequal) // !=
	Leq = BinAritOperator(lequal) // <=
	Geq = BinAritOperator(gequal) // >=
	And = BinAritOperator(and)    // &
	Or  = BinAritOperator(or)     // |
	Xor = BinAritOperator(caret)  // ^
	Shr = BinAritOperator(appOut) // >>
	Shl = BinAritOperator(hdoc)   // <<

	AndArit = BinAritOperator(andAnd) // &&
	OrArit  = BinAritOperator(orOr)   // ||
	Comma   = BinAritOperator(comma)  // ,
	Quest   = BinAritOperator(quest)  // ?
	Colon   = BinAritOperator(colon)  // :

	Assgn    = BinAritOperator(assgn)    // =
	AddAssgn = BinAritOperator(addAssgn) // +=
	SubAssgn = BinAritOperator(subAssgn) // -=
	MulAssgn = BinAritOperator(mulAssgn) // *=
	QuoAssgn = BinAritOperator(quoAssgn) // /=
	RemAssgn = BinAritOperator(remAssgn) // %=
	AndAssgn = BinAritOperator(andAssgn) // &=
	OrAssgn  = BinAritOperator(orAssgn)  // |=
	XorAssgn = BinAritOperator(xorAssgn) // ^=
	ShlAssgn = BinAritOperator(shlAssgn) // <<=
	ShrAssgn = BinAritOperator(shrAssgn) // >>=
)

type UnTestOperator token

const (
	TsExists  = UnTestOperator(tsExists) + iota // -e
	TsRegFile                                   // -f
	TsDirect                                    // -d
	TsCharSp                                    // -c
	TsBlckSp                                    // -b
	TsNmPipe                                    // -p
	TsSocket                                    // -S
	TsSmbLink                                   // -L
	TsSticky                                    // -k
	TsGIDSet                                    // -g
	TsUIDSet                                    // -u
	TsGrpOwn                                    // -G
	TsUsrOwn                                    // -O
	TsModif                                     // -N
	TsRead                                      // -r
	TsWrite                                     // -w
	TsExec                                      // -x
	TsNoEmpty                                   // -s
	TsFdTerm                                    // -t
	TsEmpStr                                    // -z
	TsNempStr                                   // -n
	TsOptSet                                    // -o
	TsVarSet                                    // -v
	TsRefVar                                    // -R
	TsNot     = UnTestOperator(exclMark)        // !
)

type BinTestOperator token

const (
	TsReMatch = BinTestOperator(tsReMatch) + iota // =~
	TsNewer                                       // -nt
	TsOlder                                       // -ot
	TsDevIno                                      // -ef
	TsEql                                         // -eq
	TsNeq                                         // -ne
	TsLeq                                         // -le
	TsGeq                                         // -ge
	TsLss                                         // -lt
	TsGtr                                         // -gt
	AndTest   = BinTestOperator(andAnd)           // &&
	OrTest    = BinTestOperator(orOr)             // ||
	TsMatch   = BinTestOperator(equal)            // ==
	TsNoMatch = BinTestOperator(nequal)           // !=
	TsBefore  = BinTestOperator(rdrIn)            // <
	TsAfter   = BinTestOperator(rdrOut)           // >
)

func (o RedirOperator) String() string    { return token(o).String() }
func (o ProcOperator) String() string     { return token(o).String() }
func (o GlobOperator) String() string     { return token(o).String() }
func (o BinCmdOperator) String() string   { return token(o).String() }
func (o CaseOperator) String() string     { return token(o).String() }
func (o ParNamesOperator) String() string { return token(o).String() }
func (o ParExpOperator) String() string   { return token(o).String() }
func (o UnAritOperator) String() string   { return token(o).String() }
func (o BinAritOperator) String() string  { return token(o).String() }
func (o UnTestOperator) String() string   { return token(o).String() }
func (o BinTestOperator) String() string  { return token(o).String() }
<|endoftext|>


<commit_before>/*
The syslog package provides a syslog client.

Unlike the core log/syslog package it uses the newer rfc5424 syslog protocol,
reliably reconnects on failure, and supports TLS encrypted TCP connections.
*/
package syslog

import (
	"crypto/tls"
	"crypto/x509"
	_ "crypto/sha512"
	"fmt"
	"io"
	"net"
	"time"
)

// A net.Conn with added reconnection logic
type conn struct {
	netConn net.Conn
	errors  chan error
}

// watch watches the connection for error, sends detected error to c.errors
func (c *conn) watch() {
	for {
		data := make([]byte, 1)
		_, err := c.netConn.Read(data)
		if err != nil {
			c.netConn.Close()
			c.errors <- err
			return
		}
	}
}

// reconnectNeeded determines if a reconnect is needed by checking for a
// message on the readErrors channel
func (c *conn) reconnectNeeded() bool {
	if c == nil {
		return true
	}
	select {
	case <-c.errors:
		return true
	default:
		return false
	}
}

// dial connects to the server and set up a watching goroutine
func dial(network, raddr string, rootCAs *x509.CertPool) (*conn, error) {
	var netConn net.Conn
	var err error

	switch network {
	case "tls":
		var config *tls.Config
		if rootCAs != nil {
			config = &tls.Config{RootCAs: rootCAs}
		}
		netConn, err = tls.Dial("tcp", raddr, config)
	case "udp", "tcp":
		netConn, err = net.Dial(network, raddr)
	default:
		return nil, fmt.Errorf("Network protocol %s not supported", network)
	}
	if err != nil {
		return nil, err
	} else {
		c := &conn{netConn, make(chan error)}
		go c.watch()
		return c, nil
	}
}

// A Logger is a connection to a syslog server. It reconnects on error.
// Clients log by sending a Packet to the logger.Packets channel.
type Logger struct {
	conn           *conn
	Packets        chan Packet
	Errors         chan error
	ClientHostname string

	network string
	raddr   string
	rootCAs *x509.CertPool
}

// Dial connects to the syslog server at raddr, using the optional certBundle,
// and launches a goroutine to watch logger.Packets for messages to log.
func Dial(clientHostname, network, raddr string, rootCAs *x509.CertPool) (*Logger, error) {
	// dial once, just to make sure the network is working
	conn, err := dial(network, raddr, rootCAs)

	if err != nil {
		return nil, err
	} else {
		logger := &Logger{
			ClientHostname: clientHostname,
			network:        network,
			raddr:          raddr,
			rootCAs:        rootCAs,
			Packets:        make(chan Packet, 100),
			Errors:         make(chan error, 0),
			conn:           conn,
		}
		go logger.writeLoop()
		return logger, nil
	}
}

// Connect to the server, retrying every 10 seconds until successful.
func (l *Logger) connect() {
	for {
		c, err := dial(l.network, l.raddr, l.rootCAs)
		if err == nil {
			l.conn = c
			return
		} else {
			l.handleError(err)
			time.Sleep(10 * time.Second)
		}
	}
	panic("unreachable")
}

// Send an error to the Error channel, but don't block if nothing is listening
func (l *Logger) handleError(err error) {
	select {
	case l.Errors <- err:
	default:
	}
}

// Write a packet, reconnecting if needed. It is not safe to call this
// method concurrently.
func (l *Logger) writePacket(p Packet) {
	var err error
	for {
		if l.conn.reconnectNeeded() {
			l.connect()
		}

		switch l.conn.netConn.(type) {
		case *net.TCPConn, *tls.Conn:
			_, err = io.WriteString(l.conn.netConn, p.Generate(0)+"\n")
		case *net.UDPConn:
			_, err = io.WriteString(l.conn.netConn, p.Generate(1024))
		default:
			panic(fmt.Errorf("Network protocol %s not supported", l.network))
		}
		if err == nil {
			return
		} else {
			l.handleError(err)
			time.Sleep(10 * time.Second)
		}
	}
}

// writeloop writes any packets recieved on l.Packets() to the syslog server.
func (l *Logger) writeLoop() {
	for p := range l.Packets {
		l.writePacket(p)
	}
}
<commit_msg>Added timeout for TCP conns<commit_after>/*
The syslog package provides a syslog client.

Unlike the core log/syslog package it uses the newer rfc5424 syslog protocol,
reliably reconnects on failure, and supports TLS encrypted TCP connections.
*/
package syslog

import (
	"crypto/tls"
	"crypto/x509"
	_ "crypto/sha512"
	"fmt"
	"io"
	"net"
	"time"
)

// A net.Conn with added reconnection logic
type conn struct {
	netConn net.Conn
	errors  chan error
}

// watch watches the connection for error, sends detected error to c.errors
func (c *conn) watch() {
	for {
		data := make([]byte, 1)
		_, err := c.netConn.Read(data)
		if err != nil {
			c.netConn.Close()
			c.errors <- err
			return
		}
	}
}

// reconnectNeeded determines if a reconnect is needed by checking for a
// message on the readErrors channel
func (c *conn) reconnectNeeded() bool {
	if c == nil {
		return true
	}
	select {
	case <-c.errors:
		return true
	default:
		return false
	}
}

// dial connects to the server and set up a watching goroutine
func dial(network, raddr string, rootCAs *x509.CertPool) (*conn, error) {
	var netConn net.Conn
	var err error

	switch network {
	case "tls":
		var config *tls.Config
		if rootCAs != nil {
			config = &tls.Config{RootCAs: rootCAs}
		}
		dialer := &net.Dialer{
			Timeout : time.Duration(30) * time.Second,
		}
		netConn, err = tls.DialWithDialer(dialer, "tcp", raddr, config)
	case "udp", "tcp":
		netConn, err = net.DialTimeout(network, raddr, time.Duration(30) * time.Second)
	default:
		return nil, fmt.Errorf("Network protocol %s not supported", network)
	}
	if err != nil {
		return nil, err
	} else {
		c := &conn{netConn, make(chan error)}
		go c.watch()
		return c, nil
	}
}

// A Logger is a connection to a syslog server. It reconnects on error.
// Clients log by sending a Packet to the logger.Packets channel.
type Logger struct {
	conn           *conn
	Packets        chan Packet
	Errors         chan error
	ClientHostname string

	network string
	raddr   string
	rootCAs *x509.CertPool
}

// Dial connects to the syslog server at raddr, using the optional certBundle,
// and launches a goroutine to watch logger.Packets for messages to log.
func Dial(clientHostname, network, raddr string, rootCAs *x509.CertPool) (*Logger, error) {
	// dial once, just to make sure the network is working
	conn, err := dial(network, raddr, rootCAs)

	if err != nil {
		return nil, err
	} else {
		logger := &Logger{
			ClientHostname: clientHostname,
			network:        network,
			raddr:          raddr,
			rootCAs:        rootCAs,
			Packets:        make(chan Packet, 100),
			Errors:         make(chan error, 0),
			conn:           conn,
		}
		go logger.writeLoop()
		return logger, nil
	}
}

// Connect to the server, retrying every 10 seconds until successful.
func (l *Logger) connect() {
	for {
		c, err := dial(l.network, l.raddr, l.rootCAs)
		if err == nil {
			l.conn = c
			return
		} else {
			l.handleError(err)
			time.Sleep(10 * time.Second)
		}
	}
	panic("unreachable")
}

// Send an error to the Error channel, but don't block if nothing is listening
func (l *Logger) handleError(err error) {
	select {
	case l.Errors <- err:
	default:
	}
}

// Write a packet, reconnecting if needed. It is not safe to call this
// method concurrently.
func (l *Logger) writePacket(p Packet) {
	var err error
	for {
		if l.conn.reconnectNeeded() {
			l.connect()
		}

		switch l.conn.netConn.(type) {
		case *net.TCPConn, *tls.Conn:
			_, err = io.WriteString(l.conn.netConn, p.Generate(0)+"\n")
		case *net.UDPConn:
			_, err = io.WriteString(l.conn.netConn, p.Generate(1024))
		default:
			panic(fmt.Errorf("Network protocol %s not supported", l.network))
		}
		if err == nil {
			return
		} else {
			l.handleError(err)
			time.Sleep(10 * time.Second)
		}
	}
}

// writeloop writes any packets recieved on l.Packets() to the syslog server.
func (l *Logger) writeLoop() {
	for p := range l.Packets {
		l.writePacket(p)
	}
}
<|endoftext|>


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

// syz-ci is a continuous fuzzing system for syzkaller.
// It runs several syz-manager's, polls and rebuilds images for managers
// and polls and rebuilds syzkaller binaries.
// For usage instructions see: docs/ci.md
package main

// Implementation details:
//
// 2 main components:
//  - SyzUpdater: handles syzkaller updates
//  - Manager: handles kernel build and syz-manager process (one per manager)
// Both operate in a similar way and keep 2 builds:
//  - latest: latest known good build (i.e. we tested it)
//    preserved across restarts/reboots, i.e. we can start fuzzing even when
//    current syzkaller/kernel git head is broken, or git is down, or anything else
//  - current: currently used build (a copy of one of the latest builds)
// Other important points:
//  - syz-ci is always built on the same revision as the rest of syzkaller binaries,
//    this allows us to handle e.g. changes in manager config format.
//  - consequently, syzkaller binaries are never updated on-the-fly,
//    instead we re-exec and then update
//  - we understand when the latest build is fresh even after reboot,
//    i.e. we store enough information to identify it (git hash, compiler identity, etc),
//    so we don't rebuild unnecessary (kernel builds take time)
//  - we generally avoid crashing the process and handle all errors gracefully
//    (this is a continuous system), except for some severe/user errors during start
//    (e.g. bad config file, or can't create necessary dirs)
//
// Directory/file structure:
// syz-ci			: current executable
// syz-ci.tag			: tag of the current executable (syzkaller git hash)
// syzkaller/
//	latest/			: latest good syzkaller build
//	current/		: syzkaller build currently in use
// managers/
//	manager1/		: one dir per manager
//		kernel/		: kernel checkout
//		workdir/	: manager workdir (never deleted)
//		latest/		: latest good kernel image build
//		current/	: kernel image currently in use
// jobs/
//	linux/			: one dir per target OS
//		kernel/		: kernel checkout
//		image/		: currently used image
//		workdir/	: some temp files
//
// Current executable, syzkaller and kernel builds are marked with tag files.
// Tag files uniquely identify the build (git hash, compiler identity, kernel config, etc).
// For tag files both contents and modification time are important,
// modification time allows us to understand if we need to rebuild after a restart.

import (
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"sync"

	"github.com/google/syzkaller/pkg/config"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/mgrconfig"
	"github.com/google/syzkaller/pkg/osutil"
)

var (
	flagConfig     = flag.String("config", "", "config file")
	flagAutoUpdate = flag.Bool("autoupdate", true, "auto-update the binary")
)

type Config struct {
	Name string `json:"name"`
	HTTP string `json:"http"`
	// If manager http address is not specified, give it an address starting from this port. Optional.
	ManagerPort     int    `json:"manager_port_start"`
	DashboardAddr   string `json:"dashboard_addr"`   // Optional.
	DashboardClient string `json:"dashboard_client"` // Optional.
	DashboardKey    string `json:"dashboard_key"`    // Optional.
	HubAddr         string `json:"hub_addr"`         // Optional.
	HubKey          string `json:"hub_key"`          // Optional.
	Goroot          string `json:"goroot"`           // Go 1.8+ toolchain dir.
	SyzkallerRepo   string `json:"syzkaller_repo"`
	SyzkallerBranch string `json:"syzkaller_branch"` // Defaults to "master".
	// Dir with additional syscall descriptions (.txt and .const files).
	SyzkallerDescriptions string `json:"syzkaller_descriptions"`
	// GCS path to upload coverage reports from managers (optional).
	CoverUploadPath string `json:"cover_upload_path"`
	// Enable patch testing jobs.
	EnableJobs bool             `json:"enable_jobs"`
	Managers   []*ManagerConfig `json:"managers"`
}

type ManagerConfig struct {
	Name            string `json:"name"`
	DashboardClient string `json:"dashboard_client"`
	DashboardKey    string `json:"dashboard_key"`
	Repo            string `json:"repo"`
	// Short name of the repo (e.g. "linux-next"), used only for reporting.
	RepoAlias    string `json:"repo_alias"`
	Branch       string `json:"branch"` // Defaults to "master".
	Compiler     string `json:"compiler"`
	Userspace    string `json:"userspace"`
	KernelConfig string `json:"kernel_config"`
	// File with kernel cmdline values (optional).
	KernelCmdline string `json:"kernel_cmdline"`
	// File with sysctl values (e.g. output of sysctl -a, optional).
	KernelSysctl  string          `json:"kernel_sysctl"`
	PollCommits   bool            `json:"poll_commits"`
	ManagerConfig json.RawMessage `json:"manager_config"`
	managercfg    *mgrconfig.Config
}

func main() {
	flag.Parse()
	log.EnableLogCaching(1000, 1<<20)
	cfg, err := loadConfig(*flagConfig)
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}

	shutdownPending := make(chan struct{})
	osutil.HandleInterrupts(shutdownPending)

	serveHTTP(cfg)

	os.Unsetenv("GOPATH")
	if cfg.Goroot != "" {
		os.Setenv("GOROOT", cfg.Goroot)
		os.Setenv("PATH", filepath.Join(cfg.Goroot, "bin")+
			string(filepath.ListSeparator)+os.Getenv("PATH"))
	}

	updatePending := make(chan struct{})
	updater := NewSyzUpdater(cfg)
	updater.UpdateOnStart(*flagAutoUpdate, shutdownPending)
	if *flagAutoUpdate {
		go func() {
			updater.WaitForUpdate()
			close(updatePending)
		}()
	}

	var wg sync.WaitGroup
	wg.Add(1)
	stop := make(chan struct{})
	go func() {
		select {
		case <-shutdownPending:
		case <-updatePending:
		}
		kernelBuildSem <- struct{}{} // wait for all current builds
		close(stop)
		wg.Done()
	}()

	var managers []*Manager
	for _, mgrcfg := range cfg.Managers {
		mgr, err := createManager(cfg, mgrcfg, stop)
		if err != nil {
			log.Logf(0, "failed to create manager %v: %v", mgrcfg.Name, err)
			continue
		}
		managers = append(managers, mgr)
	}
	if len(managers) == 0 {
		log.Fatalf("failed to create all managers")
	}
	for _, mgr := range managers {
		mgr := mgr
		wg.Add(1)
		go func() {
			defer wg.Done()
			mgr.loop()
		}()
	}

	jp := newJobProcessor(cfg, managers, stop, shutdownPending)
	wg.Add(1)
	go func() {
		defer wg.Done()
		jp.loop()
	}()

	// For testing. Racy. Use with care.
	http.HandleFunc("/upload_cover", func(w http.ResponseWriter, r *http.Request) {
		for _, mgr := range managers {
			if err := mgr.uploadCoverReport(); err != nil {
				w.Write([]byte(fmt.Sprintf("failed for %v: %v
\n", mgr.name, err)))
				return
			}
			w.Write([]byte(fmt.Sprintf("upload cover for %v
\n", mgr.name)))
		}
	})

	wg.Wait()

	select {
	case <-shutdownPending:
	case <-updatePending:
		updater.UpdateAndRestart()
	}
}

func serveHTTP(cfg *Config) {
	ln, err := net.Listen("tcp4", cfg.HTTP)
	if err != nil {
		log.Fatalf("failed to listen on %v: %v", cfg.HTTP, err)
	}
	log.Logf(0, "serving http on http://%v", ln.Addr())
	go func() {
		err := http.Serve(ln, nil)
		log.Fatalf("failed to serve http: %v", err)
	}()
}

func loadConfig(filename string) (*Config, error) {
	cfg := &Config{
		SyzkallerRepo:   "https://github.com/google/syzkaller.git",
		SyzkallerBranch: "master",
		ManagerPort:     10000,
		Goroot:          os.Getenv("GOROOT"),
	}
	if err := config.LoadFile(filename, cfg); err != nil {
		return nil, err
	}
	if cfg.Name == "" {
		return nil, fmt.Errorf("param 'name' is empty")
	}
	if cfg.HTTP == "" {
		return nil, fmt.Errorf("param 'http' is empty")
	}
	if len(cfg.Managers) == 0 {
		return nil, fmt.Errorf("no managers specified")
	}
	if cfg.EnableJobs && (cfg.DashboardAddr == "" || cfg.DashboardClient == "") {
		return nil, fmt.Errorf("enabled_jobs is set but no dashboard info")
	}
	for i, mgr := range cfg.Managers {
		if mgr.Name == "" {
			return nil, fmt.Errorf("param 'managers[%v].name' is empty", i)
		}
		if mgr.Branch == "" {
			mgr.Branch = "master"
		}
		managercfg, err := mgrconfig.LoadPartialData(mgr.ManagerConfig)
		if err != nil {
			return nil, fmt.Errorf("manager %v: %v", mgr.Name, err)
		}
		if mgr.PollCommits && (cfg.DashboardAddr == "" || mgr.DashboardClient == "") {
			return nil, fmt.Errorf("manager %v: commit_poll is set but no dashboard info", mgr.Name)
		}
		mgr.managercfg = managercfg
		managercfg.Name = cfg.Name + "-" + mgr.Name
		managercfg.Syzkaller = filepath.FromSlash("syzkaller/current")
		if managercfg.HTTP == "" {
			managercfg.HTTP = fmt.Sprintf(":%v", cfg.ManagerPort)
			cfg.ManagerPort++
		}
	}
	return cfg, nil
}
<commit_msg>syz-ci: add flag that allows to not start managers<commit_after>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// syz-ci is a continuous fuzzing system for syzkaller.
// It runs several syz-manager's, polls and rebuilds images for managers
// and polls and rebuilds syzkaller binaries.
// For usage instructions see: docs/ci.md
package main

// Implementation details:
//
// 2 main components:
//  - SyzUpdater: handles syzkaller updates
//  - Manager: handles kernel build and syz-manager process (one per manager)
// Both operate in a similar way and keep 2 builds:
//  - latest: latest known good build (i.e. we tested it)
//    preserved across restarts/reboots, i.e. we can start fuzzing even when
//    current syzkaller/kernel git head is broken, or git is down, or anything else
//  - current: currently used build (a copy of one of the latest builds)
// Other important points:
//  - syz-ci is always built on the same revision as the rest of syzkaller binaries,
//    this allows us to handle e.g. changes in manager config format.
//  - consequently, syzkaller binaries are never updated on-the-fly,
//    instead we re-exec and then update
//  - we understand when the latest build is fresh even after reboot,
//    i.e. we store enough information to identify it (git hash, compiler identity, etc),
//    so we don't rebuild unnecessary (kernel builds take time)
//  - we generally avoid crashing the process and handle all errors gracefully
//    (this is a continuous system), except for some severe/user errors during start
//    (e.g. bad config file, or can't create necessary dirs)
//
// Directory/file structure:
// syz-ci			: current executable
// syz-ci.tag			: tag of the current executable (syzkaller git hash)
// syzkaller/
//	latest/			: latest good syzkaller build
//	current/		: syzkaller build currently in use
// managers/
//	manager1/		: one dir per manager
//		kernel/		: kernel checkout
//		workdir/	: manager workdir (never deleted)
//		latest/		: latest good kernel image build
//		current/	: kernel image currently in use
// jobs/
//	linux/			: one dir per target OS
//		kernel/		: kernel checkout
//		image/		: currently used image
//		workdir/	: some temp files
//
// Current executable, syzkaller and kernel builds are marked with tag files.
// Tag files uniquely identify the build (git hash, compiler identity, kernel config, etc).
// For tag files both contents and modification time are important,
// modification time allows us to understand if we need to rebuild after a restart.

import (
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"sync"

	"github.com/google/syzkaller/pkg/config"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/mgrconfig"
	"github.com/google/syzkaller/pkg/osutil"
)

var (
	flagConfig     = flag.String("config", "", "config file")
	flagAutoUpdate = flag.Bool("autoupdate", true, "auto-update the binary (for testing)")
	flagManagers   = flag.Bool("managers", true, "start managers (for testing)")
)

type Config struct {
	Name string `json:"name"`
	HTTP string `json:"http"`
	// If manager http address is not specified, give it an address starting from this port. Optional.
	ManagerPort     int    `json:"manager_port_start"`
	DashboardAddr   string `json:"dashboard_addr"`   // Optional.
	DashboardClient string `json:"dashboard_client"` // Optional.
	DashboardKey    string `json:"dashboard_key"`    // Optional.
	HubAddr         string `json:"hub_addr"`         // Optional.
	HubKey          string `json:"hub_key"`          // Optional.
	Goroot          string `json:"goroot"`           // Go 1.8+ toolchain dir.
	SyzkallerRepo   string `json:"syzkaller_repo"`
	SyzkallerBranch string `json:"syzkaller_branch"` // Defaults to "master".
	// Dir with additional syscall descriptions (.txt and .const files).
	SyzkallerDescriptions string `json:"syzkaller_descriptions"`
	// GCS path to upload coverage reports from managers (optional).
	CoverUploadPath string `json:"cover_upload_path"`
	// Enable patch testing jobs.
	EnableJobs bool             `json:"enable_jobs"`
	Managers   []*ManagerConfig `json:"managers"`
}

type ManagerConfig struct {
	Name            string `json:"name"`
	DashboardClient string `json:"dashboard_client"`
	DashboardKey    string `json:"dashboard_key"`
	Repo            string `json:"repo"`
	// Short name of the repo (e.g. "linux-next"), used only for reporting.
	RepoAlias    string `json:"repo_alias"`
	Branch       string `json:"branch"` // Defaults to "master".
	Compiler     string `json:"compiler"`
	Userspace    string `json:"userspace"`
	KernelConfig string `json:"kernel_config"`
	// File with kernel cmdline values (optional).
	KernelCmdline string `json:"kernel_cmdline"`
	// File with sysctl values (e.g. output of sysctl -a, optional).
	KernelSysctl  string          `json:"kernel_sysctl"`
	PollCommits   bool            `json:"poll_commits"`
	ManagerConfig json.RawMessage `json:"manager_config"`
	managercfg    *mgrconfig.Config
}

func main() {
	flag.Parse()
	log.EnableLogCaching(1000, 1<<20)
	cfg, err := loadConfig(*flagConfig)
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}

	shutdownPending := make(chan struct{})
	osutil.HandleInterrupts(shutdownPending)

	serveHTTP(cfg)

	os.Unsetenv("GOPATH")
	if cfg.Goroot != "" {
		os.Setenv("GOROOT", cfg.Goroot)
		os.Setenv("PATH", filepath.Join(cfg.Goroot, "bin")+
			string(filepath.ListSeparator)+os.Getenv("PATH"))
	}

	updatePending := make(chan struct{})
	updater := NewSyzUpdater(cfg)
	updater.UpdateOnStart(*flagAutoUpdate, shutdownPending)
	if *flagAutoUpdate {
		go func() {
			updater.WaitForUpdate()
			close(updatePending)
		}()
	}

	var wg sync.WaitGroup
	wg.Add(1)
	stop := make(chan struct{})
	go func() {
		select {
		case <-shutdownPending:
		case <-updatePending:
		}
		kernelBuildSem <- struct{}{} // wait for all current builds
		close(stop)
		wg.Done()
	}()

	var managers []*Manager
	for _, mgrcfg := range cfg.Managers {
		mgr, err := createManager(cfg, mgrcfg, stop)
		if err != nil {
			log.Logf(0, "failed to create manager %v: %v", mgrcfg.Name, err)
			continue
		}
		managers = append(managers, mgr)
	}
	if len(managers) == 0 {
		log.Fatalf("failed to create all managers")
	}
	if *flagManagers {
		for _, mgr := range managers {
			mgr := mgr
			wg.Add(1)
			go func() {
				defer wg.Done()
				mgr.loop()
			}()
		}
	}

	jp := newJobProcessor(cfg, managers, stop, shutdownPending)
	wg.Add(1)
	go func() {
		defer wg.Done()
		jp.loop()
	}()

	// For testing. Racy. Use with care.
	http.HandleFunc("/upload_cover", func(w http.ResponseWriter, r *http.Request) {
		for _, mgr := range managers {
			if err := mgr.uploadCoverReport(); err != nil {
				w.Write([]byte(fmt.Sprintf("failed for %v: %v
\n", mgr.name, err)))
				return
			}
			w.Write([]byte(fmt.Sprintf("upload cover for %v
\n", mgr.name)))
		}
	})

	wg.Wait()

	select {
	case <-shutdownPending:
	case <-updatePending:
		updater.UpdateAndRestart()
	}
}

func serveHTTP(cfg *Config) {
	ln, err := net.Listen("tcp4", cfg.HTTP)
	if err != nil {
		log.Fatalf("failed to listen on %v: %v", cfg.HTTP, err)
	}
	log.Logf(0, "serving http on http://%v", ln.Addr())
	go func() {
		err := http.Serve(ln, nil)
		log.Fatalf("failed to serve http: %v", err)
	}()
}

func loadConfig(filename string) (*Config, error) {
	cfg := &Config{
		SyzkallerRepo:   "https://github.com/google/syzkaller.git",
		SyzkallerBranch: "master",
		ManagerPort:     10000,
		Goroot:          os.Getenv("GOROOT"),
	}
	if err := config.LoadFile(filename, cfg); err != nil {
		return nil, err
	}
	if cfg.Name == "" {
		return nil, fmt.Errorf("param 'name' is empty")
	}
	if cfg.HTTP == "" {
		return nil, fmt.Errorf("param 'http' is empty")
	}
	if len(cfg.Managers) == 0 {
		return nil, fmt.Errorf("no managers specified")
	}
	if cfg.EnableJobs && (cfg.DashboardAddr == "" || cfg.DashboardClient == "") {
		return nil, fmt.Errorf("enabled_jobs is set but no dashboard info")
	}
	for i, mgr := range cfg.Managers {
		if mgr.Name == "" {
			return nil, fmt.Errorf("param 'managers[%v].name' is empty", i)
		}
		if mgr.Branch == "" {
			mgr.Branch = "master"
		}
		managercfg, err := mgrconfig.LoadPartialData(mgr.ManagerConfig)
		if err != nil {
			return nil, fmt.Errorf("manager %v: %v", mgr.Name, err)
		}
		if mgr.PollCommits && (cfg.DashboardAddr == "" || mgr.DashboardClient == "") {
			return nil, fmt.Errorf("manager %v: commit_poll is set but no dashboard info", mgr.Name)
		}
		mgr.managercfg = managercfg
		managercfg.Name = cfg.Name + "-" + mgr.Name
		managercfg.Syzkaller = filepath.FromSlash("syzkaller/current")
		if managercfg.HTTP == "" {
			managercfg.HTTP = fmt.Sprintf(":%v", cfg.ManagerPort)
			cfg.ManagerPort++
		}
	}
	return cfg, nil
}
<|endoftext|>


<commit_before>package tablet

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	config "github.com/ASPecherkin/TabletHive/hiveConfig"
	result "github.com/ASPecherkin/TabletHive/storeResults"
	"github.com/davecgh/go-spew/spew"
)

//Ride - basic struct for Mobile controller responce
type Ride struct {
	ID        uint        `json:"id"`
	Number    string      `json:"number"`
	Duration  uint        `json:"duration"`
	Distance  float32     `json:"distance"`
	FactRides []FactRides `json:"fact_rides"`
}

// FactRides - struct for json unmarshal FactRides in responce
type FactRides struct {
	ID         uint        `json:"id"`
	TimeStart  string      `json:"time_start"`
	RidePoints []RidePoint `json:"ride_points"`
}

// RidePoint - struct for json unmarshal RidePoint in responce
type RidePoint struct {
	ID          uint    `json:"id"`
	Number      uint    `json:"number"`
	Lat         float32 `json:"lat"`
	Lng         float32 `json:"lng"`
	AddressText string  `json:"address_text"`
	Status      string  `json:"status"`
	Kind        string  `json:"kind"`
	Order       `json:"order"`
}

// Order - struct for json unmarshal Order in responce
type Order struct {
	ID            uint   `json:"id"`
	Status        string `json:"status"`
	ServiceType   string `json:"service_type"`
	ServiceObject `json:"service_object"`
}

// ServiceObject - struct for json unmarshal ServiceObject in responce
type ServiceObject struct {
	ID      uint   `json:"id"`
	Name    string `json:"name"`
	ObjType string `json:"type"`
	TimeT   string `json:"time_t"`
	Phones  string `json:"phones"`
	TimeG1  string `json:"time_g1"`
	TimeG2  string `json:"time_g2"`
}

// Device one unit of hive
//  "device":{"name":"", "device_code":"nomer", "registration_id":"id"}
//curl -H 'Content-Type: application/json'  -X POST "https://strela-dev-alpha.at-consulting.ru/mobile/devices" -d '{"device":{"name":"test","device_code":"1", "registration_id":"45"}' -v
type Device struct {
	ID         string
	Name       string
	Token      string
	RespObj    Ride
	Rawresp    string
	StatusCode int
	Login      string
	ch         chan string
}

// InitDevice generate all needed data for Device
func (t *Device) InitDevice(cfg *config.HiveConfig) error {
	type responce struct {
		Code     string `json:"code"`
		MsgError string `json:"msgError"`
		Login    string `json:"login"`
		Token    string `json:"token"`
	}
	type device struct {
		Name       string `json:"name"`
		DeviceCode string `json:"device_code"`
		RegID      string `json:"registration_id"`
	}
	//  client := &http.Client{}
	url := strings.Join(append([]string{cfg.ServerURL, cfg.Endpoints["register"].URL}), "")
	req, err := http.NewRequest("POST", url, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")

	return nil
}

// GetRide create connect amd get ride for that token
func (t *Device) GetRide(wg *sync.WaitGroup, cfg *config.HiveConfig, res chan result.Result) error {
	defer wg.Done()
	client := &http.Client{}
	url := strings.Join(append([]string{cfg.ServerURL, cfg.Endpoints["get_rides"].URL, t.ID}), "")
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	request.Header.Add("X-Sadira-Auth-Token", t.Token)
	time.Sleep(time.Duration(cfg.Endpoints["get_rides"].Delay))
	start := time.Now()
	responce, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	}
	jsonData, err := ioutil.ReadAll(responce.Body)
	res <- result.Result{RequestType: "GET_RIDE", AuthToken: t.Token, RequestURL: url, RequestStatus: responce.StatusCode, ProcessedTime: time.Since(start).Seconds()}
	defer responce.Body.Close()
	if err != nil && err != io.EOF {
		fmt.Println("error reading from responce Body", err)
		return err
	}
	t.StatusCode = responce.StatusCode
	if responce.StatusCode == 404 {
		t.Rawresp = string(jsonData)
		return nil
	} else if responce.StatusCode == 200 {
		var answer Ride
		err = json.Unmarshal([]byte(jsonData), &answer)
		if err != nil {
			spew.Printf("err: %s  with token : %v when unmarhal this  \n", err, t)
		}
		t.RespObj, t.Rawresp = answer, string(jsonData)
		return nil
	} else {
		t.Rawresp = string(jsonData)
		return nil
	}
}
<commit_msg>delete tablet.go<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/decred/dcrd/limits"
)

var (
	cfg             *config
	shutdownChannel = make(chan struct{})
)

// winServiceMain is only invoked on Windows.  It detects when dcrd is running
// as a service and reacts accordingly.
var winServiceMain func() (bool, error)

// dcrdMain is the real main function for dcrd.  It is necessary to work around
// the fact that deferred functions do not run when os.Exit() is called.  The
// optional serverChan parameter is mainly used by the service code to be
// notified with the server once it is setup so it can gracefully stop it when
// requested from the service control manager.
func dcrdMain(serverChan chan<- *server) error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer backendLog.Flush()

	// Show version at startup.
	dcrdLog.Infof("Version %s", version())

	// Enable http profiling server if requested.
	if cfg.Profile != "" {
		go func() {
			listenAddr := net.JoinHostPort("", cfg.Profile)
			dcrdLog.Infof("Creating profiling server "+
				"listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			err := http.ListenAndServe(listenAddr, nil)
			if err != nil {
				fatalf(err.Error())
			}
		}()
	}

	// Write cpu profile if requested.
	if cfg.CPUProfile != "" {
		f, err := os.Create(cfg.CPUProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create cpu profile: %v", err.Error())
			return err
		}
		pprof.StartCPUProfile(f)
		defer f.Close()
		defer pprof.StopCPUProfile()
	}

	// Write mem profile if requested.
	if cfg.MemProfile != "" {
		f, err := os.Create(cfg.MemProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create cpu profile: %v", err)
			return err
		}
		timer := time.NewTimer(time.Minute * 20) // 20 minutes
		go func() {
			<-timer.C
			pprof.WriteHeapProfile(f)
			f.Close()
		}()
	}

	// Perform upgrades to dcrd as new versions require it.
	if err := doUpgrades(); err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}

	// Load the block database.
	db, err := loadBlockDB()
	if err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}
	defer db.Close()

	if cfg.DropAddrIndex {
		dcrdLog.Info("Deleting entire addrindex.")
		err := db.PurgeAddrIndex()
		if err != nil {
			dcrdLog.Errorf("Unable to delete the addrindex: %v", err)
			return err
		}
		dcrdLog.Info("Successfully deleted addrindex, exiting")
		return nil
	}

	tmdb, err := loadTicketDB(db, activeNetParams.Params)
	if err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}
	defer tmdb.Close()

	// Ensure the databases are sync'd and closed on Ctrl+C.
	addInterruptHandler(func() {
		dcrdLog.Infof("Gracefully shutting down the database...")
		err := tmdb.Store(cfg.DataDir, "ticketdb.gob")
		if err != nil {
			dcrdLog.Errorf("Failed to store ticket database: %v", err.Error())
		}
		db.RollbackClose()
	})

	// Create server and start it.
	server, err := newServer(cfg.Listeners, db, tmdb, activeNetParams.Params)
	if err != nil {
		// TODO(oga) this logging could do with some beautifying.
		dcrdLog.Errorf("Unable to start server on %v: %v",
			cfg.Listeners, err)
		return err
	}
	addInterruptHandler(func() {
		dcrdLog.Infof("Gracefully shutting down the server...")
		server.Stop()
		server.WaitForShutdown()
	})
	server.Start()
	if serverChan != nil {
		serverChan <- server
	}

	// Monitor for graceful server shutdown and signal the main goroutine
	// when done.  This is done in a separate goroutine rather than waiting
	// directly so the main goroutine can be signaled for shutdown by either
	// a graceful shutdown or from the main interrupt handler.  This is
	// necessary since the main goroutine must be kept running long enough
	// for the interrupt handler goroutine to finish.
	go func() {
		server.WaitForShutdown()
		srvrLog.Infof("Server shutdown complete")
		shutdownChannel <- struct{}{}
	}()

	// Wait for shutdown signal from either a graceful server stop or from
	// the interrupt handler.
	<-shutdownChannel
	dcrdLog.Info("Shutdown complete")
	return nil
}

func main() {
	// Use all processor cores.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Up some limits.
	if err := limits.SetLimits(); err != nil {
		os.Exit(1)
	}

	// Call serviceMain on Windows to handle running as a service.  When
	// the return isService flag is true, exit now since we ran as a
	// service.  Otherwise, just fall through to normal operation.
	if runtime.GOOS == "windows" {
		isService, err := winServiceMain()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if isService {
			os.Exit(0)
		}
	}

	// Work around defer not working after os.Exit()
	if err := dcrdMain(nil); err != nil {
		os.Exit(1)
	}
}
<commit_msg>Fix storing the ticket database to disk on close<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/decred/dcrd/limits"
)

var (
	cfg             *config
	shutdownChannel = make(chan struct{})
)

// winServiceMain is only invoked on Windows.  It detects when dcrd is running
// as a service and reacts accordingly.
var winServiceMain func() (bool, error)

// dcrdMain is the real main function for dcrd.  It is necessary to work around
// the fact that deferred functions do not run when os.Exit() is called.  The
// optional serverChan parameter is mainly used by the service code to be
// notified with the server once it is setup so it can gracefully stop it when
// requested from the service control manager.
func dcrdMain(serverChan chan<- *server) error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer backendLog.Flush()

	// Show version at startup.
	dcrdLog.Infof("Version %s", version())

	// Enable http profiling server if requested.
	if cfg.Profile != "" {
		go func() {
			listenAddr := net.JoinHostPort("", cfg.Profile)
			dcrdLog.Infof("Creating profiling server "+
				"listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			err := http.ListenAndServe(listenAddr, nil)
			if err != nil {
				fatalf(err.Error())
			}
		}()
	}

	// Write cpu profile if requested.
	if cfg.CPUProfile != "" {
		f, err := os.Create(cfg.CPUProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create cpu profile: %v", err.Error())
			return err
		}
		pprof.StartCPUProfile(f)
		defer f.Close()
		defer pprof.StopCPUProfile()
	}

	// Write mem profile if requested.
	if cfg.MemProfile != "" {
		f, err := os.Create(cfg.MemProfile)
		if err != nil {
			dcrdLog.Errorf("Unable to create cpu profile: %v", err)
			return err
		}
		timer := time.NewTimer(time.Minute * 20) // 20 minutes
		go func() {
			<-timer.C
			pprof.WriteHeapProfile(f)
			f.Close()
		}()
	}

	// Perform upgrades to dcrd as new versions require it.
	if err := doUpgrades(); err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}

	// Load the block database.
	db, err := loadBlockDB()
	if err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}
	defer db.Close()

	if cfg.DropAddrIndex {
		dcrdLog.Info("Deleting entire addrindex.")
		err := db.PurgeAddrIndex()
		if err != nil {
			dcrdLog.Errorf("Unable to delete the addrindex: %v", err)
			return err
		}
		dcrdLog.Info("Successfully deleted addrindex, exiting")
		return nil
	}

	tmdb, err := loadTicketDB(db, activeNetParams.Params)
	if err != nil {
		dcrdLog.Errorf("%v", err)
		return err
	}
	defer func() {
		err := tmdb.Store(cfg.DataDir, "ticketdb.gob")
		if err != nil {
			dcrdLog.Errorf("Failed to store ticket database: %v", err.Error())
		}
	}()
	defer tmdb.Close()

	// Ensure the databases are sync'd and closed on Ctrl+C.
	addInterruptHandler(func() {
		dcrdLog.Infof("Gracefully shutting down the database...")
		db.RollbackClose()
	})

	// Create server and start it.
	server, err := newServer(cfg.Listeners, db, tmdb, activeNetParams.Params)
	if err != nil {
		// TODO(oga) this logging could do with some beautifying.
		dcrdLog.Errorf("Unable to start server on %v: %v",
			cfg.Listeners, err)
		return err
	}
	addInterruptHandler(func() {
		dcrdLog.Infof("Gracefully shutting down the server...")
		server.Stop()
		server.WaitForShutdown()
	})
	server.Start()
	if serverChan != nil {
		serverChan <- server
	}

	// Monitor for graceful server shutdown and signal the main goroutine
	// when done.  This is done in a separate goroutine rather than waiting
	// directly so the main goroutine can be signaled for shutdown by either
	// a graceful shutdown or from the main interrupt handler.  This is
	// necessary since the main goroutine must be kept running long enough
	// for the interrupt handler goroutine to finish.
	go func() {
		server.WaitForShutdown()
		srvrLog.Infof("Server shutdown complete")
		shutdownChannel <- struct{}{}
	}()

	// Wait for shutdown signal from either a graceful server stop or from
	// the interrupt handler.
	<-shutdownChannel
	dcrdLog.Info("Shutdown complete")
	return nil
}

func main() {
	// Use all processor cores.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Up some limits.
	if err := limits.SetLimits(); err != nil {
		os.Exit(1)
	}

	// Call serviceMain on Windows to handle running as a service.  When
	// the return isService flag is true, exit now since we ran as a
	// service.  Otherwise, just fall through to normal operation.
	if runtime.GOOS == "windows" {
		isService, err := winServiceMain()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if isService {
			os.Exit(0)
		}
	}

	// Work around defer not working after os.Exit()
	if err := dcrdMain(nil); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package amonagent

import (
	"log"
	"sync"
	"time"

	"github.com/martinrusev/amonagent/collectors"
	"github.com/martinrusev/amonagent/core"
	"github.com/martinrusev/amonagent/remote"
)

// Agent - XXX
type Agent struct {
	// Interval at which to gather information
	Interval time.Duration
}

// GatherAndSend - XXX
func (a *Agent) GatherAndSend() error {

	allMetrics := collectors.CollectSystem()
	remote.SendData(allMetrics)
	return nil
}

// NewAgent - XXX
func NewAgent(config core.SettingsStruct) (*Agent, error) {
	agent := &Agent{
		Interval: 10 * time.Second,
	}

	return agent, nil
}

// Run runs the agent daemon, gathering every Interval
func (a *Agent) Run(shutdown chan struct{}) error {
	var wg sync.WaitGroup

	log.Printf("Agent Config: Interval:%s\n", a.Interval)

	ticker := time.NewTicker(a.Interval)

	wg.Add(1)
	go func() {
		defer wg.Done()
		if err := a.GatherAndSend(); err != nil {
			log.Printf("Flusher routine failed, exiting: %s\n", err.Error())
			close(shutdown)
		}
	}()

	defer wg.Wait()

	for {

		select {
		case <-shutdown:
			return nil
		case <-ticker.C:
			continue
		}
	}
}
<commit_msg>Fix agent interval<commit_after>package amonagent

import (
	"log"
	"time"

	"github.com/martinrusev/amonagent/collectors"
	"github.com/martinrusev/amonagent/core"
	"github.com/martinrusev/amonagent/remote"
)

// Agent - XXX
type Agent struct {
	// Interval at which to gather information
	Interval time.Duration
}

// GatherAndSend - XXX
func (a *Agent) GatherAndSend() error {

	allMetrics := collectors.CollectSystem()
	remote.SendData(allMetrics)
	return nil
}

// NewAgent - XXX
func NewAgent(config core.SettingsStruct) (*Agent, error) {
	agent := &Agent{
		Interval: 10 * time.Second,
	}

	return agent, nil
}

// Run runs the agent daemon, gathering every Interval
func (a *Agent) Run(shutdown chan struct{}) error {

	log.Printf("Agent Config: Interval:%s\n", a.Interval)

	ticker := time.NewTicker(a.Interval)

	for {

		if err := a.GatherAndSend(); err != nil {
			log.Printf("Flusher routine failed, exiting: %s\n", err.Error())
		}
		select {
		case <-shutdown:
			return nil
		case <-ticker.C:
			continue
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/bjwschaap/docker-events-syslog/dess"
	"github.com/urfave/cli"
)

func main() {
	log.SetOutput(os.Stdout)

	app := cli.NewApp()
	app.Name = "dess"
	app.Usage = "Daemon that forwards Docker events to Splunk"
	app.Version = "0.1.0"
	app.Copyright = "(C)2016 Bastiaan Schaap"
	app.Author = "Bastiaan Schaap"
	app.Email = "bastiaan.schaap@gmail.com"
	app.UsageText = `./dess -s 123.123.1.2:4873 -u user -p pass
	 This daemon uses DOCKER_HOST, DOCKER_CERT_PATH and DOCKER_TLS settings to connect to the Docker daemon.
   Optionally you can override Docker settings with --host, --certs and --tls.`

	// Define the configuration flags the program can/should use
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "host,H",
			Value:  "unix:///var/run/docker.sock",
			Usage:  "Address or location of the Docker API endpoint",
			EnvVar: "DOCKER_HOST",
		},
		cli.StringFlag{
			Name:   "certs,c",
			Value:  "",
			Usage:  "Location of TLS certificates for connecting with Docker",
			EnvVar: "DOCKER_CERT_PATH",
		},
		cli.BoolFlag{
			Name:   "tls",
			Usage:  "Should TLS be used for connecting to Docker",
			EnvVar: "DOCKER_TLS_VERIFY",
		},
	}

	// Set the main program logic
	app.Action = func(c *cli.Context) error {
		return dess.Start(c)
	}

	// Now start doing stuff
	app.Run(os.Args)
}
<commit_msg>Change example usage<commit_after>package main

import (
	"log"
	"os"

	"github.com/bjwschaap/docker-events-syslog/dess"
	"github.com/urfave/cli"
)

func main() {
	log.SetOutput(os.Stdout)

	app := cli.NewApp()
	app.Name = "dess"
	app.Usage = "Daemon that forwards Docker events to Splunk"
	app.Version = "0.1.0"
	app.Copyright = "(C)2016 Bastiaan Schaap"
	app.Author = "Bastiaan Schaap"
	app.Email = "bastiaan.schaap@gmail.com"
	app.UsageText = `./dess
	 This daemon uses DOCKER_HOST, DOCKER_CERT_PATH and DOCKER_TLS settings to connect to the Docker daemon.
   Optionally you can override Docker settings with --host, --certs and --tls.`

	// Define the configuration flags the program can/should use
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "host,H",
			Value:  "unix:///var/run/docker.sock",
			Usage:  "Address or location of the Docker API endpoint",
			EnvVar: "DOCKER_HOST",
		},
		cli.StringFlag{
			Name:   "certs,c",
			Value:  "",
			Usage:  "Location of TLS certificates for connecting with Docker",
			EnvVar: "DOCKER_CERT_PATH",
		},
		cli.BoolFlag{
			Name:   "tls",
			Usage:  "Should TLS be used for connecting to Docker",
			EnvVar: "DOCKER_TLS_VERIFY",
		},
	}

	// Set the main program logic
	app.Action = func(c *cli.Context) error {
		return dess.Start(c)
	}

	// Now start doing stuff
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Xiaomi Corporation. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 *
 * Authors:    Yu Bo <yubo@xiaomi.com>
 */
package govs

import (
	"fmt"
	"strings"
)

type Vs_dest_user struct {
	Nic         uint8
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
}

type Vs_dest_user_r struct {
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
	Activeconns uint32
	Inactconns  uint32
	Persistent  uint32
	Conns       uint64
	Inpkts      uint64
	Outpkts     uint64
	Inbytes     uint64
	Outbytes    uint64
}

const (
	fmt_dest_t = "%5s %21s %8s %8s %15s %12s %12s %12s %7s %10s %10s %10s %10s"
	fmt_dest   = "%5s %21s %08x %8d %15s %12d %12d %12d %7d %10d %10d %10d %10d"
)

func Dest_title() string {
	return fmt.Sprintf(fmt_dest_t,
		"->", "Addr:Port", "Flags", "Weight", "threshold",
		"Activeconns", "Inactconns", "Persistent",
		"Conns", "Inpkts", "Outpkts", "Inbytes", "Outbytes")
}

func (d Vs_dest_user_r) String() string {
	return fmt.Sprintf(fmt_dest,
		"->", fmt.Sprintf("%s:%s", d.Addr.String(), d.Port.String()), d.Conn_flags,
		d.Weight, fmt.Sprintf("%d-%d", d.L_threshold, d.U_threshold),
		d.Activeconns, d.Inactconns, d.Persistent,
		d.Conns, d.Inpkts, d.Outpkts, d.Inbytes, d.Outbytes)
}

type Vs_list_dests_r struct {
	Code  int
	Msg   string
	Dests []Vs_dest_user_r
}

func (r Vs_list_dests_r) String() string {
	var s string
	if r.Code != 0 {
		return fmt.Sprintf("%s:%s", Ecode(r.Code), r.Msg)
	}
	for _, dest := range r.Dests {
		s += fmt.Sprintf("%s\n", dest)
	}

	return strings.TrimRight(s, "\n")
}

func Get_dests(o *CmdOptions) (*Vs_list_dests_r, error) {
	var reply Vs_list_dests_r
	args := Vs_list_q{
		Cmd: VS_CMD_GET_DEST,
		Service: Vs_service_user{
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
			Protocol: uint8(o.Protocol),
			Number:   o.Number,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

type Vs_dest_q struct {
	Cmd     int
	Service Vs_service_user
	Dest    Vs_dest_user
}

func Set_adddest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_NEW_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_editdest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_SET_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Addr.Ip,
			Port:        o.Addr.Port,
			Conn_flags:  o.Conn_flags,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_deldest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_DEL_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Addr: o.Addr.Ip,
			Port: o.Addr.Port,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}
<commit_msg>fix: edit realserver<commit_after>/*
 * Copyright 2016 Xiaomi Corporation. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 *
 * Authors:    Yu Bo <yubo@xiaomi.com>
 */
package govs

import (
	"fmt"
	"strings"
)

type Vs_dest_user struct {
	Nic         uint8
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
}

type Vs_dest_user_r struct {
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
	Activeconns uint32
	Inactconns  uint32
	Persistent  uint32
	Conns       uint64
	Inpkts      uint64
	Outpkts     uint64
	Inbytes     uint64
	Outbytes    uint64
}

const (
	fmt_dest_t = "%5s %21s %8s %8s %15s %12s %12s %12s %7s %10s %10s %10s %10s"
	fmt_dest   = "%5s %21s %08x %8d %15s %12d %12d %12d %7d %10d %10d %10d %10d"
)

func Dest_title() string {
	return fmt.Sprintf(fmt_dest_t,
		"->", "Addr:Port", "Flags", "Weight", "threshold",
		"Activeconns", "Inactconns", "Persistent",
		"Conns", "Inpkts", "Outpkts", "Inbytes", "Outbytes")
}

func (d Vs_dest_user_r) String() string {
	return fmt.Sprintf(fmt_dest,
		"->", fmt.Sprintf("%s:%s", d.Addr.String(), d.Port.String()), d.Conn_flags,
		d.Weight, fmt.Sprintf("%d-%d", d.L_threshold, d.U_threshold),
		d.Activeconns, d.Inactconns, d.Persistent,
		d.Conns, d.Inpkts, d.Outpkts, d.Inbytes, d.Outbytes)
}

type Vs_list_dests_r struct {
	Code  int
	Msg   string
	Dests []Vs_dest_user_r
}

func (r Vs_list_dests_r) String() string {
	var s string
	if r.Code != 0 {
		return fmt.Sprintf("%s:%s", Ecode(r.Code), r.Msg)
	}
	for _, dest := range r.Dests {
		s += fmt.Sprintf("%s\n", dest)
	}

	return strings.TrimRight(s, "\n")
}

func Get_dests(o *CmdOptions) (*Vs_list_dests_r, error) {
	var reply Vs_list_dests_r
	args := Vs_list_q{
		Cmd: VS_CMD_GET_DEST,
		Service: Vs_service_user{
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
			Protocol: uint8(o.Protocol),
			Number:   o.Number,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

type Vs_dest_q struct {
	Cmd     int
	Service Vs_service_user
	Dest    Vs_dest_user
}

func Set_adddest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_NEW_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_editdest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_SET_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_deldest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_DEL_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Addr: o.Addr.Ip,
			Port: o.Addr.Port,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}
<|endoftext|>


<commit_before>package option

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
)

// The PutObjectInput type is an adapter to change a parameter in
// s3.PutObjectInput.
type PutObjectInput func(req *s3.PutObjectInput)

// SSEKMSKeyID returns a PutObjectInput that changes a SSE-KMS Key ID.
func SSEKMSKeyID(keyID string) PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.SSEKMSKeyId = aws.String(keyID)
	}
}

// ACLPrivate returns a PutObjectInput that set ACL private.
func ACLPrivate() PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.ACL = aws.String(s3.ObjectCannedACLPrivate)
	}
}

// ContentType returns a PutObjectInput that set Content-Type.
func ContentType(ct string) PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.ContentType = aws.String(ct)
	}
}

// ContentLength returns a PutObjectInput that set Content-Length.
func ContentLength(length int) PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.ContentLength = aws.Int64(int64(length))
	}
}
<commit_msg>Use int64 instead<commit_after>package option

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
)

// The PutObjectInput type is an adapter to change a parameter in
// s3.PutObjectInput.
type PutObjectInput func(req *s3.PutObjectInput)

// SSEKMSKeyID returns a PutObjectInput that changes a SSE-KMS Key ID.
func SSEKMSKeyID(keyID string) PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.SSEKMSKeyId = aws.String(keyID)
	}
}

// ACLPrivate returns a PutObjectInput that set ACL private.
func ACLPrivate() PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.ACL = aws.String(s3.ObjectCannedACLPrivate)
	}
}

// ContentType returns a PutObjectInput that set Content-Type.
func ContentType(ct string) PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.ContentType = aws.String(ct)
	}
}

// ContentLength returns a PutObjectInput that set Content-Length.
func ContentLength(length int64) PutObjectInput {
	return func(req *s3.PutObjectInput) {
		req.ContentLength = aws.Int64(length)
	}
}
<|endoftext|>


<commit_before>// +build !windows

package opendkim

/*
#cgo LDFLAGS: -L/usr/local/opt/opendkim/lib -lopendkim
#cgo CFLAGS: -g -O2 -Wno-error -I/opt/local/include/opendkim/ -I/usr/include/opendkim/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <opendkim/dkim.h>
*/
import "C"

import (
	"bytes"
	"fmt"
	"io"
	"net/mail"
	"runtime"
	"sync"
	"unsafe"
)

type (
	Canon   int
	Sign    int
	Op      int
	Option  int
	Sigflag uint
)

const (
	CanonUNKNOWN Canon = (-1) // unknown method
	CanonSIMPLE  Canon = 0    // as specified in DKIM spec
	CanonRELAXED Canon = 1    // as specified in DKIM spec
)

const (
	SignUNKNOWN   Sign = -2 // unknown method
	SignDEFAULT   Sign = -1 // use internal default
	SignRSASHA1   Sign = 0  // an RSA-signed SHA1 digest
	SignRSASHA256 Sign = 1  // an RSA-signed SHA256 digest
)

const (
	StatusOK            = 0  // function completed successfully
	StatusBADSIG        = 1  // signature available but failed
	StatusNOSIG         = 2  // no signature available
	StatusNOKEY         = 3  // public key not found
	StatusCANTVRFY      = 4  // can't get domain key to verify
	StatusSYNTAX        = 5  // message is not valid syntax
	StatusNORESOURCE    = 6  // resource unavailable
	StatusINTERNAL      = 7  // internal error
	StatusREVOKED       = 8  // key found, but revoked
	StatusINVALID       = 9  // invalid function parameter
	StatusNOTIMPLEMENT  = 10 // function not implemented
	StatusKEYFAIL       = 11 // key retrieval failed
	StatusCBREJECT      = 12 // callback requested reject
	StatusCBINVALID     = 13 // callback gave invalid result
	StatusCBTRYAGAIN    = 14 // callback says try again later
	StatusCBERROR       = 15 // callback error
	StatusMULTIDNSREPLY = 16 // multiple DNS replies
	StatusSIGGEN        = 17 // signature generation failed
)

const (
	OptionFLAGS        Option = 0
	OptionTMPDIR       Option = 1
	OptionTIMEOUT      Option = 2
	OptionSENDERHDRS   Option = 3
	OptionSIGNHDRS     Option = 4
	OptionOVERSIGNHDRS Option = 5
	OptionQUERYMETHOD  Option = 6
	OptionQUERYINFO    Option = 7
	OptionFIXEDTIME    Option = 8
	OptionSKIPHDRS     Option = 9
	OptionALWAYSHDRS   Option = 10 // obsolete
	OptionSIGNATURETTL Option = 11
	OptionCLOCKDRIFT   Option = 12
	OptionMUSTBESIGNED Option = 13
	OptionMINKEYBITS   Option = 14
	OptionREQUIREDHDRS Option = 15
)

const (
	LibflagsNONE          = 0x0000
	LibflagsTMPFILES      = 0x0001
	LibflagsKEEPFILES     = 0x0002
	LibflagsSIGNLEN       = 0x0004
	LibflagsCACHE         = 0x0008
	LibflagsZTAGS         = 0x0010
	LibflagsDELAYSIGPROC  = 0x0020
	LibflagsEOHCHECK      = 0x0040
	LibflagsACCEPTV05     = 0x0080
	LibflagsFIXCRLF       = 0x0100
	LibflagsACCEPTDK      = 0x0200
	LibflagsBADSIGHANDLES = 0x0400
	LibflagsVERIFYONE     = 0x0800
	LibflagsSTRICTHDRS    = 0x1000
	LibflagsREPORTBADADSP = 0x2000
	LibflagsDROPSIGNER    = 0x4000
	LibflagsSTRICTRESIGN  = 0x8000
)

const (
	SigflagIGNORE      = 0x01
	SigflagPROCESSED   = 0x02
	SigflagPASSED      = 0x04
	SigflagTESTKEY     = 0x08
	SigflagNOSUBDOMAIN = 0x10
	SigflagKEYLOADED   = 0x20
)

const (
	QueryUNKNOWN = (-1) // unknown method
	QueryDNS     = 0    // DNS query method (per the draft)
	QueryFILE    = 1    // text file method (for testing)
)

const (
	GetOpt Op = 0
	SetOpt Op = 1
)

// Lib is a dkim library handle
type Lib struct {
	lib *C.struct_DKIM_LIB
	mtx sync.Mutex
}

// Init inits a new dkim library handle
func Init() *Lib {
	lib := new(Lib)
	lib.lib = C.dkim_init(nil, nil)
	if lib.lib == nil {
		panic("could not init libopendkim")
	}
	runtime.SetFinalizer(lib, func(l *Lib) {
		l.Close()
	})
	return lib
}

// Options sets or gets library options
func (lib *Lib) Options(op Op, opt Option, ptr unsafe.Pointer, size uintptr) {
	lib.mtx.Lock()
	defer lib.mtx.Unlock()

	C.dkim_options(lib.lib, C.int(op), C.dkim_opts_t(opt), ptr, C.size_t(size))
}

// Close closes the dkim lib
func (lib *Lib) Close() {
	lib.mtx.Lock()
	defer lib.mtx.Unlock()

	if lib.lib != nil {
		C.dkim_close(lib.lib)
		lib.lib = nil
	}
}

// Dkim handle
type Dkim struct {
	dkim *C.DKIM
	mtx  sync.Mutex
}

// NewSigner creates a new DKIM handle for message signing.
// If -1 is specified for bytesToSign, the whole message body will be signed.
func (lib *Lib) NewSigner(secret, selector, domain string, hdrCanon, bodyCanon Canon, algo Sign, bytesToSign int64) (*Dkim, Status) {
	var stat C.DKIM_STAT

	signer := new(Dkim)
	signer.dkim = C.dkim_sign(
		lib.lib,
		nil,
		nil,
		(*C.uchar)(unsafe.Pointer(C.CString(secret))),
		(*C.uchar)(unsafe.Pointer(C.CString(selector))),
		(*C.uchar)(unsafe.Pointer(C.CString(domain))),
		C.dkim_canon_t(hdrCanon),
		C.dkim_canon_t(bodyCanon),
		C.dkim_alg_t(algo),
		C.ssize_t(bytesToSign),
		&stat,
	)

	s := Status(stat)
	if s != StatusOK {
		return nil, s
	}
	runtime.SetFinalizer(signer, func(s *Dkim) {
		s.Destroy()
	})
	return signer, s
}

// NewVerifier creates a new DKIM verifier
func (lib *Lib) NewVerifier() (*Dkim, Status) {
	var stat C.DKIM_STAT

	vrfy := new(Dkim)
	vrfy.dkim = C.dkim_verify(lib.lib, nil, nil, &stat)

	s := Status(stat)
	if s != StatusOK {
		return nil, s
	}
	runtime.SetFinalizer(vrfy, func(s *Dkim) {
		s.Destroy()
	})
	return vrfy, s
}

// Sign is a helper method for signing a block of message data.
// The message data includes header and body.
func (d *Dkim) Sign(r io.Reader) ([]byte, error) {
	hdr, body, stat := d.process(r)
	if stat != StatusOK {
		return nil, stat
	}

	sigHdr, stat := d.GetSigHdr()
	if stat != StatusOK {
		return nil, stat
	}

	hdr.WriteString(`DKIM-Signature: ` + sigHdr + "\r\n\r\n")

	var out bytes.Buffer
	io.Copy(&out, hdr)
	io.Copy(&out, body)

	return out.Bytes(), nil
}

// Verify is a helper method for verifying a message in one step
func (d *Dkim) Verify(r io.Reader) Status {
	_, _, stat := d.process(r)
	return stat
}

func (d *Dkim) process(r io.Reader) (hdr, body *bytes.Buffer, stat Status) {
	msg, err := mail.ReadMessage(r)
	if err != nil {
		return nil, nil, Status(StatusINTERNAL)
	}
	hdr = bytes.NewBuffer(nil)
	for k, vv := range msg.Header {
		for _, v := range vv {
			h := k + `: ` + v
			stat = d.Header(h)
			if stat != StatusOK {
				return
			}
			hdr.WriteString(h + "\r\n")
		}
	}

	stat = d.Eoh()
	if stat != StatusOK {
		return
	}

	body = bytes.NewBuffer(nil)
	io.Copy(body, msg.Body)

	stat = d.Body(body.Bytes())
	if stat != StatusOK {
		return
	}
	stat = d.Eom(nil)
	return
}

// Header processes a single header line.
// May be invoked multiple times.
func (d *Dkim) Header(line string) Status {
	data := []byte(line)
	return Status(C.dkim_header(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data))))
}

// Eoh is called to signal end of header.
func (d *Dkim) Eoh() Status {
	return Status(C.dkim_eoh(d.dkim))
}

// Body processes the message body.
func (d *Dkim) Body(data []byte) Status {
	return Status(C.dkim_body(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data))))
}

// Eom is called to signal end of message.
func (d *Dkim) Eom(testKey *bool) Status {
	return Status(C.dkim_eom(d.dkim, (*C._Bool)(testKey)))
}

// Chunk processes a chunk of message data.
// Can include header and body data.
//
// TODO: disabled until I figure out what's fould here
//
// func (d *Dkim) Chunk(data []byte) error {
// 	var stat C.DKIM_STAT
// 	stat = C.dkim_chunk(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 	if stat != StatusOK {
// 		return fmt.Errorf("error processing chunk (%s)", getErr(stat))
// 	}
// 	return nil
// }

// GetSigHdr computes the signature header for a message.
func (d *Dkim) GetSigHdr() (string, Status) {
	var buf = make([]byte, 1024)
	stat := Status(C.dkim_getsighdr(d.dkim, (*C.u_char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), C.size_t(0)))
	if stat != StatusOK {
		return "", stat
	}
	i := bytes.Index(buf, []byte{0x0})
	if i >= 0 {
		return string(buf[:i]), stat
	}
	return string(buf), stat
}

// GetSignature returns the signature.
// Eom must be called before invoking GetSignature.
func (d *Dkim) GetSignature() *Signature {
	var sig *C.DKIM_SIGINFO
	sig = C.dkim_getsignature(d.dkim)
	if sig == nil {
		return nil
	}
	return &Signature{
		h:   d,
		sig: sig,
	}
}

// GetError gets the last error for the dkim handle
func (d *Dkim) GetError() string {
	return C.GoString(C.dkim_geterror(d.dkim))
}

// Destroy destroys the dkim handle.
func (d *Dkim) Destroy() Status {
	d.mtx.Lock()
	defer d.mtx.Unlock()

	if d.dkim != nil {
		stat := Status(C.dkim_free(d.dkim))
		if stat != StatusOK {
			return stat
		}
		d.dkim = nil
	}
	return Status(StatusOK)
}

// Signature is a DKIM signature
type Signature struct {
	h   *Dkim
	sig *C.DKIM_SIGINFO
}

// Process processes a signature for validity.
func (s *Signature) Process() Status {
	return Status(C.dkim_sig_process(s.h.dkim, s.sig))
}

// Flags returns the signature flags
func (s *Signature) Flags() Sigflag {
	var res C.uint
	res = C.dkim_sig_getflags(s.sig)
	return Sigflag(res)
}

func getErr(s C.DKIM_STAT) string {
	return Status(s).Error()
}

type Status int

func (s Status) String() string {
	return fmt.Sprintf("%d: %s", s, C.GoString(C.dkim_getresultstr(C.DKIM_STAT(s))))
}

func (s Status) Error() string {
	return s.String()
}
<commit_msg>Changed struct_DKIM_LIB to DKIM_LIB for newer Go versions.<commit_after>// +build !windows

package opendkim

/*
#cgo LDFLAGS: -L/usr/local/opt/opendkim/lib -lopendkim
#cgo CFLAGS: -g -O2 -Wno-error -I/opt/local/include/opendkim/ -I/usr/include/opendkim/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <opendkim/dkim.h>
*/
import "C"

import (
	"bytes"
	"fmt"
	"io"
	"net/mail"
	"runtime"
	"sync"
	"unsafe"
)

type (
	Canon   int
	Sign    int
	Op      int
	Option  int
	Sigflag uint
)

const (
	CanonUNKNOWN Canon = (-1) // unknown method
	CanonSIMPLE  Canon = 0    // as specified in DKIM spec
	CanonRELAXED Canon = 1    // as specified in DKIM spec
)

const (
	SignUNKNOWN   Sign = -2 // unknown method
	SignDEFAULT   Sign = -1 // use internal default
	SignRSASHA1   Sign = 0  // an RSA-signed SHA1 digest
	SignRSASHA256 Sign = 1  // an RSA-signed SHA256 digest
)

const (
	StatusOK            = 0  // function completed successfully
	StatusBADSIG        = 1  // signature available but failed
	StatusNOSIG         = 2  // no signature available
	StatusNOKEY         = 3  // public key not found
	StatusCANTVRFY      = 4  // can't get domain key to verify
	StatusSYNTAX        = 5  // message is not valid syntax
	StatusNORESOURCE    = 6  // resource unavailable
	StatusINTERNAL      = 7  // internal error
	StatusREVOKED       = 8  // key found, but revoked
	StatusINVALID       = 9  // invalid function parameter
	StatusNOTIMPLEMENT  = 10 // function not implemented
	StatusKEYFAIL       = 11 // key retrieval failed
	StatusCBREJECT      = 12 // callback requested reject
	StatusCBINVALID     = 13 // callback gave invalid result
	StatusCBTRYAGAIN    = 14 // callback says try again later
	StatusCBERROR       = 15 // callback error
	StatusMULTIDNSREPLY = 16 // multiple DNS replies
	StatusSIGGEN        = 17 // signature generation failed
)

const (
	OptionFLAGS        Option = 0
	OptionTMPDIR       Option = 1
	OptionTIMEOUT      Option = 2
	OptionSENDERHDRS   Option = 3
	OptionSIGNHDRS     Option = 4
	OptionOVERSIGNHDRS Option = 5
	OptionQUERYMETHOD  Option = 6
	OptionQUERYINFO    Option = 7
	OptionFIXEDTIME    Option = 8
	OptionSKIPHDRS     Option = 9
	OptionALWAYSHDRS   Option = 10 // obsolete
	OptionSIGNATURETTL Option = 11
	OptionCLOCKDRIFT   Option = 12
	OptionMUSTBESIGNED Option = 13
	OptionMINKEYBITS   Option = 14
	OptionREQUIREDHDRS Option = 15
)

const (
	LibflagsNONE          = 0x0000
	LibflagsTMPFILES      = 0x0001
	LibflagsKEEPFILES     = 0x0002
	LibflagsSIGNLEN       = 0x0004
	LibflagsCACHE         = 0x0008
	LibflagsZTAGS         = 0x0010
	LibflagsDELAYSIGPROC  = 0x0020
	LibflagsEOHCHECK      = 0x0040
	LibflagsACCEPTV05     = 0x0080
	LibflagsFIXCRLF       = 0x0100
	LibflagsACCEPTDK      = 0x0200
	LibflagsBADSIGHANDLES = 0x0400
	LibflagsVERIFYONE     = 0x0800
	LibflagsSTRICTHDRS    = 0x1000
	LibflagsREPORTBADADSP = 0x2000
	LibflagsDROPSIGNER    = 0x4000
	LibflagsSTRICTRESIGN  = 0x8000
)

const (
	SigflagIGNORE      = 0x01
	SigflagPROCESSED   = 0x02
	SigflagPASSED      = 0x04
	SigflagTESTKEY     = 0x08
	SigflagNOSUBDOMAIN = 0x10
	SigflagKEYLOADED   = 0x20
)

const (
	QueryUNKNOWN = (-1) // unknown method
	QueryDNS     = 0    // DNS query method (per the draft)
	QueryFILE    = 1    // text file method (for testing)
)

const (
	GetOpt Op = 0
	SetOpt Op = 1
)

// Lib is a dkim library handle
type Lib struct {
	lib *C.DKIM_LIB
	mtx sync.Mutex
}

// Init inits a new dkim library handle
func Init() *Lib {
	lib := new(Lib)
	lib.lib = C.dkim_init(nil, nil)
	if lib.lib == nil {
		panic("could not init libopendkim")
	}
	runtime.SetFinalizer(lib, func(l *Lib) {
		l.Close()
	})
	return lib
}

// Options sets or gets library options
func (lib *Lib) Options(op Op, opt Option, ptr unsafe.Pointer, size uintptr) {
	lib.mtx.Lock()
	defer lib.mtx.Unlock()

	C.dkim_options(lib.lib, C.int(op), C.dkim_opts_t(opt), ptr, C.size_t(size))
}

// Close closes the dkim lib
func (lib *Lib) Close() {
	lib.mtx.Lock()
	defer lib.mtx.Unlock()

	if lib.lib != nil {
		C.dkim_close(lib.lib)
		lib.lib = nil
	}
}

// Dkim handle
type Dkim struct {
	dkim *C.DKIM
	mtx  sync.Mutex
}

// NewSigner creates a new DKIM handle for message signing.
// If -1 is specified for bytesToSign, the whole message body will be signed.
func (lib *Lib) NewSigner(secret, selector, domain string, hdrCanon, bodyCanon Canon, algo Sign, bytesToSign int64) (*Dkim, Status) {
	var stat C.DKIM_STAT

	signer := new(Dkim)
	signer.dkim = C.dkim_sign(
		lib.lib,
		nil,
		nil,
		(*C.uchar)(unsafe.Pointer(C.CString(secret))),
		(*C.uchar)(unsafe.Pointer(C.CString(selector))),
		(*C.uchar)(unsafe.Pointer(C.CString(domain))),
		C.dkim_canon_t(hdrCanon),
		C.dkim_canon_t(bodyCanon),
		C.dkim_alg_t(algo),
		C.ssize_t(bytesToSign),
		&stat,
	)

	s := Status(stat)
	if s != StatusOK {
		return nil, s
	}
	runtime.SetFinalizer(signer, func(s *Dkim) {
		s.Destroy()
	})
	return signer, s
}

// NewVerifier creates a new DKIM verifier
func (lib *Lib) NewVerifier() (*Dkim, Status) {
	var stat C.DKIM_STAT

	vrfy := new(Dkim)
	vrfy.dkim = C.dkim_verify(lib.lib, nil, nil, &stat)

	s := Status(stat)
	if s != StatusOK {
		return nil, s
	}
	runtime.SetFinalizer(vrfy, func(s *Dkim) {
		s.Destroy()
	})
	return vrfy, s
}

// Sign is a helper method for signing a block of message data.
// The message data includes header and body.
func (d *Dkim) Sign(r io.Reader) ([]byte, error) {
	hdr, body, stat := d.process(r)
	if stat != StatusOK {
		return nil, stat
	}

	sigHdr, stat := d.GetSigHdr()
	if stat != StatusOK {
		return nil, stat
	}

	hdr.WriteString(`DKIM-Signature: ` + sigHdr + "\r\n\r\n")

	var out bytes.Buffer
	io.Copy(&out, hdr)
	io.Copy(&out, body)

	return out.Bytes(), nil
}

// Verify is a helper method for verifying a message in one step
func (d *Dkim) Verify(r io.Reader) Status {
	_, _, stat := d.process(r)
	return stat
}

func (d *Dkim) process(r io.Reader) (hdr, body *bytes.Buffer, stat Status) {
	msg, err := mail.ReadMessage(r)
	if err != nil {
		return nil, nil, Status(StatusINTERNAL)
	}
	hdr = bytes.NewBuffer(nil)
	for k, vv := range msg.Header {
		for _, v := range vv {
			h := k + `: ` + v
			stat = d.Header(h)
			if stat != StatusOK {
				return
			}
			hdr.WriteString(h + "\r\n")
		}
	}

	stat = d.Eoh()
	if stat != StatusOK {
		return
	}

	body = bytes.NewBuffer(nil)
	io.Copy(body, msg.Body)

	stat = d.Body(body.Bytes())
	if stat != StatusOK {
		return
	}
	stat = d.Eom(nil)
	return
}

// Header processes a single header line.
// May be invoked multiple times.
func (d *Dkim) Header(line string) Status {
	data := []byte(line)
	return Status(C.dkim_header(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data))))
}

// Eoh is called to signal end of header.
func (d *Dkim) Eoh() Status {
	return Status(C.dkim_eoh(d.dkim))
}

// Body processes the message body.
func (d *Dkim) Body(data []byte) Status {
	return Status(C.dkim_body(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data))))
}

// Eom is called to signal end of message.
func (d *Dkim) Eom(testKey *bool) Status {
	return Status(C.dkim_eom(d.dkim, (*C._Bool)(testKey)))
}

// Chunk processes a chunk of message data.
// Can include header and body data.
//
// TODO: disabled until I figure out what's fould here
//
// func (d *Dkim) Chunk(data []byte) error {
// 	var stat C.DKIM_STAT
// 	stat = C.dkim_chunk(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 	if stat != StatusOK {
// 		return fmt.Errorf("error processing chunk (%s)", getErr(stat))
// 	}
// 	return nil
// }

// GetSigHdr computes the signature header for a message.
func (d *Dkim) GetSigHdr() (string, Status) {
	var buf = make([]byte, 1024)
	stat := Status(C.dkim_getsighdr(d.dkim, (*C.u_char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), C.size_t(0)))
	if stat != StatusOK {
		return "", stat
	}
	i := bytes.Index(buf, []byte{0x0})
	if i >= 0 {
		return string(buf[:i]), stat
	}
	return string(buf), stat
}

// GetSignature returns the signature.
// Eom must be called before invoking GetSignature.
func (d *Dkim) GetSignature() *Signature {
	var sig *C.DKIM_SIGINFO
	sig = C.dkim_getsignature(d.dkim)
	if sig == nil {
		return nil
	}
	return &Signature{
		h:   d,
		sig: sig,
	}
}

// GetError gets the last error for the dkim handle
func (d *Dkim) GetError() string {
	return C.GoString(C.dkim_geterror(d.dkim))
}

// Destroy destroys the dkim handle.
func (d *Dkim) Destroy() Status {
	d.mtx.Lock()
	defer d.mtx.Unlock()

	if d.dkim != nil {
		stat := Status(C.dkim_free(d.dkim))
		if stat != StatusOK {
			return stat
		}
		d.dkim = nil
	}
	return Status(StatusOK)
}

// Signature is a DKIM signature
type Signature struct {
	h   *Dkim
	sig *C.DKIM_SIGINFO
}

// Process processes a signature for validity.
func (s *Signature) Process() Status {
	return Status(C.dkim_sig_process(s.h.dkim, s.sig))
}

// Flags returns the signature flags
func (s *Signature) Flags() Sigflag {
	var res C.uint
	res = C.dkim_sig_getflags(s.sig)
	return Sigflag(res)
}

func getErr(s C.DKIM_STAT) string {
	return Status(s).Error()
}

type Status int

func (s Status) String() string {
	return fmt.Sprintf("%d: %s", s, C.GoString(C.dkim_getresultstr(C.DKIM_STAT(s))))
}

func (s Status) Error() string {
	return s.String()
}
<|endoftext|>