Source file
src/net/nss.go
1
2
3
4
5
6
7 package net
8
9 import (
10 "errors"
11 "internal/bytealg"
12 "io"
13 "os"
14 )
15
16
17 type nssConf struct {
18 err error
19 sources map[string][]nssSource
20 }
21
22 type nssSource struct {
23 source string
24 criteria []nssCriterion
25 }
26
27
28
29 func (s nssSource) standardCriteria() bool {
30 for i, crit := range s.criteria {
31 if !crit.standardStatusAction(i == len(s.criteria)-1) {
32 return false
33 }
34 }
35 return true
36 }
37
38
39
40 type nssCriterion struct {
41 negate bool
42 status string
43 action string
44 }
45
46
47
48
49 func (c nssCriterion) standardStatusAction(last bool) bool {
50 if c.negate {
51 return false
52 }
53 var def string
54 switch c.status {
55 case "success":
56 def = "return"
57 case "notfound", "unavail", "tryagain":
58 def = "continue"
59 default:
60
61 return false
62 }
63 if last && c.action == "return" {
64 return true
65 }
66 return c.action == def
67 }
68
69 func parseNSSConfFile(file string) *nssConf {
70 f, err := os.Open(file)
71 if err != nil {
72 return &nssConf{err: err}
73 }
74 defer f.Close()
75 return parseNSSConf(f)
76 }
77
78 func parseNSSConf(r io.Reader) *nssConf {
79 slurp, err := readFull(r)
80 if err != nil {
81 return &nssConf{err: err}
82 }
83 conf := new(nssConf)
84 conf.err = foreachLine(slurp, func(line []byte) error {
85 line = trimSpace(removeComment(line))
86 if len(line) == 0 {
87 return nil
88 }
89 colon := bytealg.IndexByte(line, ':')
90 if colon == -1 {
91 return errors.New("no colon on line")
92 }
93 db := string(trimSpace(line[:colon]))
94 srcs := line[colon+1:]
95 for {
96 srcs = trimSpace(srcs)
97 if len(srcs) == 0 {
98 break
99 }
100 sp := bytealg.IndexByte(srcs, ' ')
101 var src string
102 if sp == -1 {
103 src = string(srcs)
104 srcs = nil
105 } else {
106 src = string(srcs[:sp])
107 srcs = trimSpace(srcs[sp+1:])
108 }
109 var criteria []nssCriterion
110
111 if len(srcs) > 0 && srcs[0] == '[' {
112 bclose := bytealg.IndexByte(srcs, ']')
113 if bclose == -1 {
114 return errors.New("unclosed criterion bracket")
115 }
116 var err error
117 criteria, err = parseCriteria(srcs[1:bclose])
118 if err != nil {
119 return errors.New("invalid criteria: " + string(srcs[1:bclose]))
120 }
121 srcs = srcs[bclose+1:]
122 }
123 if conf.sources == nil {
124 conf.sources = make(map[string][]nssSource)
125 }
126 conf.sources[db] = append(conf.sources[db], nssSource{
127 source: src,
128 criteria: criteria,
129 })
130 }
131 return nil
132 })
133 return conf
134 }
135
136
137 func parseCriteria(x []byte) (c []nssCriterion, err error) {
138 err = foreachField(x, func(f []byte) error {
139 not := false
140 if len(f) > 0 && f[0] == '!' {
141 not = true
142 f = f[1:]
143 }
144 if len(f) < 3 {
145 return errors.New("criterion too short")
146 }
147 eq := bytealg.IndexByte(f, '=')
148 if eq == -1 {
149 return errors.New("criterion lacks equal sign")
150 }
151 lowerASCIIBytes(f)
152 c = append(c, nssCriterion{
153 negate: not,
154 status: string(f[:eq]),
155 action: string(f[eq+1:]),
156 })
157 return nil
158 })
159 return
160 }
161
View as plain text