...
Run Format

Source file src/net/nss.go

     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.
     4	
     5	// +build darwin dragonfly freebsd linux netbsd openbsd solaris
     6	
     7	package net
     8	
     9	import (
    10		"errors"
    11		"io"
    12		"os"
    13	)
    14	
    15	// nssConf represents the state of the machine's /etc/nsswitch.conf file.
    16	type nssConf struct {
    17		err     error                  // any error encountered opening or parsing the file
    18		sources map[string][]nssSource // keyed by database (e.g. "hosts")
    19	}
    20	
    21	type nssSource struct {
    22		source   string // e.g. "compat", "files", "mdns4_minimal"
    23		criteria []nssCriterion
    24	}
    25	
    26	// standardCriteria reports all specified criteria have the default
    27	// status actions.
    28	func (s nssSource) standardCriteria() bool {
    29		for i, crit := range s.criteria {
    30			if !crit.standardStatusAction(i == len(s.criteria)-1) {
    31				return false
    32			}
    33		}
    34		return true
    35	}
    36	
    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)
    43	}
    44	
    45	// standardStatusAction reports whether c is equivalent to not
    46	// specifying the criterion at all. last is whether this criteria is the
    47	// last in the list.
    48	func (c nssCriterion) standardStatusAction(last bool) bool {
    49		if c.negate {
    50			return false
    51		}
    52		var def string
    53		switch c.status {
    54		case "success":
    55			def = "return"
    56		case "notfound", "unavail", "tryagain":
    57			def = "continue"
    58		default:
    59			// Unknown status
    60			return false
    61		}
    62		if last && c.action == "return" {
    63			return true
    64		}
    65		return c.action == def
    66	}
    67	
    68	func parseNSSConfFile(file string) *nssConf {
    69		f, err := os.Open(file)
    70		if err != nil {
    71			return &nssConf{err: err}
    72		}
    73		defer f.Close()
    74		return parseNSSConf(f)
    75	}
    76	
    77	func parseNSSConf(r io.Reader) *nssConf {
    78		slurp, err := readFull(r)
    79		if err != nil {
    80			return &nssConf{err: err}
    81		}
    82		conf := new(nssConf)
    83		conf.err = foreachLine(slurp, func(line []byte) error {
    84			line = trimSpace(removeComment(line))
    85			if len(line) == 0 {
    86				return nil
    87			}
    88			colon := bytesIndexByte(line, ':')
    89			if colon == -1 {
    90				return errors.New("no colon on line")
    91			}
    92			db := string(trimSpace(line[:colon]))
    93			srcs := line[colon+1:]
    94			for {
    95				srcs = trimSpace(srcs)
    96				if len(srcs) == 0 {
    97					break
    98				}
    99				sp := bytesIndexByte(srcs, ' ')
   100				var src string
   101				if sp == -1 {
   102					src = string(srcs)
   103					srcs = nil // done
   104				} else {
   105					src = string(srcs[:sp])
   106					srcs = trimSpace(srcs[sp+1:])
   107				}
   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, ']')
   112					if bclose == -1 {
   113						return errors.New("unclosed criterion bracket")
   114					}
   115					var err error
   116					criteria, err = parseCriteria(srcs[1:bclose])
   117					if err != nil {
   118						return errors.New("invalid criteria: " + string(srcs[1:bclose]))
   119					}
   120					srcs = srcs[bclose+1:]
   121				}
   122				if conf.sources == nil {
   123					conf.sources = make(map[string][]nssSource)
   124				}
   125				conf.sources[db] = append(conf.sources[db], nssSource{
   126					source:   src,
   127					criteria: criteria,
   128				})
   129			}
   130			return nil
   131		})
   132		return conf
   133	}
   134	
   135	// parses "foo=bar !foo=bar"
   136	func parseCriteria(x []byte) (c []nssCriterion, err error) {
   137		err = foreachField(x, func(f []byte) error {
   138			not := false
   139			if len(f) > 0 && f[0] == '!' {
   140				not = true
   141				f = f[1:]
   142			}
   143			if len(f) < 3 {
   144				return errors.New("criterion too short")
   145			}
   146			eq := bytesIndexByte(f, '=')
   147			if eq == -1 {
   148				return errors.New("criterion lacks equal sign")
   149			}
   150			lowerASCIIBytes(f)
   151			c = append(c, nssCriterion{
   152				negate: not,
   153				status: string(f[:eq]),
   154				action: string(f[eq+1:]),
   155			})
   156			return nil
   157		})
   158		return
   159	}
   160	

View as plain text