1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
15 // nssConf represents the state of the machine's /etc/nsswitch.conf file.
17 err error
// any error encountered opening or parsing the file
18 sources
map[string][]nssSource
// keyed by database (e.g. "hosts")
21 type nssSource
struct {
22 source
string // e.g. "compat", "files", "mdns4_minimal"
23 criteria
[]nssCriterion
26 // standardCriteria reports all specified criteria have the default
28 func (s nssSource
) standardCriteria() bool {
29 for i
, crit
:= range s
.criteria
{
30 if !crit
.standardStatusAction(i
== len(s
.criteria
)-1) {
37 // nssCriterion is the parsed structure of one of the criteria in brackets
38 // after an NSS source name.
39 type nssCriterion
struct {
40 negate
bool // if "!" was present
41 status
string // e.g. "success", "unavail" (lowercase)
42 action
string // e.g. "return", "continue" (lowercase)
45 // standardStatusAction reports whether c is equivalent to not
46 // specifying the criterion at all. last is whether this criteria is the
48 func (c nssCriterion
) standardStatusAction(last
bool) bool {
56 case "notfound", "unavail", "tryagain":
62 if last
&& c
.action
== "return" {
65 return c
.action
== def
68 func parseNSSConfFile(file
string) *nssConf
{
69 f
, err
:= os
.Open(file
)
71 return &nssConf
{err
: err
}
74 return parseNSSConf(f
)
77 func parseNSSConf(r io
.Reader
) *nssConf
{
78 slurp
, err
:= readFull(r
)
80 return &nssConf
{err
: err
}
83 conf
.err
= foreachLine(slurp
, func(line
[]byte) error
{
84 line
= trimSpace(removeComment(line
))
88 colon
:= bytesIndexByte(line
, ':')
90 return errors
.New("no colon on line")
92 db
:= string(trimSpace(line
[:colon
]))
93 srcs
:= line
[colon
+1:]
95 srcs
= trimSpace(srcs
)
99 sp
:= bytesIndexByte(srcs
, ' ')
105 src
= string(srcs
[:sp
])
106 srcs
= trimSpace(srcs
[sp
+1:])
108 var criteria
[]nssCriterion
109 // See if there's a criteria block in brackets.
110 if len(srcs
) > 0 && srcs
[0] == '[' {
111 bclose
:= bytesIndexByte(srcs
, ']')
113 return errors
.New("unclosed criterion bracket")
116 criteria
, err
= parseCriteria(srcs
[1:bclose
])
118 return errors
.New("invalid criteria: " + string(srcs
[1:bclose
]))
120 srcs
= srcs
[bclose
+1:]
122 if conf
.sources
== nil {
123 conf
.sources
= make(map[string][]nssSource
)
125 conf
.sources
[db
] = append(conf
.sources
[db
], nssSource
{
135 // parses "foo=bar !foo=bar"
136 func parseCriteria(x
[]byte) (c
[]nssCriterion
, err error
) {
137 err
= foreachField(x
, func(f
[]byte) error
{
139 if len(f
) > 0 && f
[0] == '!' {
144 return errors
.New("criterion too short")
146 eq
:= bytesIndexByte(f
, '=')
148 return errors
.New("criterion lacks equal sign")
151 c
= append(c
, nssCriterion
{
153 status
: string(f
[:eq
]),
154 action
: string(f
[eq
+1:]),