149 lines
2.9 KiB
Go
149 lines
2.9 KiB
Go
package ifupdown
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
type Interfaces map[string]*NetworkInterface
|
|
|
|
func (i Interfaces) buf() *bytes.Buffer {
|
|
buf := &bytes.Buffer{}
|
|
for _, iface := range i {
|
|
err := iface.write(func(s string) { _, _ = buf.Write([]byte(s)) })
|
|
if err != nil && !errors.Is(err, io.EOF) {
|
|
panic(err)
|
|
}
|
|
_, _ = buf.Write([]byte("\n"))
|
|
}
|
|
return buf
|
|
}
|
|
|
|
func (i Interfaces) Read(p []byte) (int, error) {
|
|
buf := i.buf()
|
|
defer pools.Buffers.Put(buf)
|
|
return buf.Read(p)
|
|
}
|
|
|
|
func (i Interfaces) String() string {
|
|
buf := i.buf()
|
|
defer pools.Buffers.Put(buf)
|
|
return buf.String()
|
|
}
|
|
|
|
func (i Interfaces) UnmarshalJSON(data []byte) error {
|
|
var ifaces map[string]*NetworkInterface
|
|
if err := json.Unmarshal(data, &ifaces); err != nil {
|
|
return err
|
|
}
|
|
for name, iface := range ifaces {
|
|
iface.Name = name
|
|
iface.allocated = true
|
|
i[name] = iface
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type MultiParser struct {
|
|
Interfaces map[string]*NetworkInterface
|
|
Errs []error
|
|
buf []byte
|
|
mu *sync.Mutex
|
|
}
|
|
|
|
func NewMultiParser() *MultiParser {
|
|
return &MultiParser{
|
|
Interfaces: make(Interfaces),
|
|
Errs: make([]error, 0),
|
|
buf: make([]byte, 0),
|
|
mu: &sync.Mutex{},
|
|
}
|
|
}
|
|
|
|
func (p *MultiParser) Write(data []byte) (int, error) {
|
|
p.mu.Lock()
|
|
p.buf = append(p.buf, data...)
|
|
p.mu.Unlock()
|
|
return len(data), nil
|
|
}
|
|
|
|
func (p *MultiParser) Parse() (Interfaces, error) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
scanner := bufio.NewScanner(strings.NewReader(string(p.buf)))
|
|
|
|
index := 0
|
|
currentIfaceName := ""
|
|
|
|
buf := pools.Buffers.Get()
|
|
defer pools.Buffers.Put(buf)
|
|
|
|
flush := func(name string) (*NetworkInterface, bool) {
|
|
if len(buf.Bytes()) == 0 {
|
|
return nil, false
|
|
}
|
|
defer buf.Reset()
|
|
newIface := NewNetworkInterface(name)
|
|
if _, err := buf.WriteTo(newIface); err != nil {
|
|
p.Errs = append(p.Errs, err)
|
|
return nil, false
|
|
}
|
|
p.Interfaces[newIface.Name] = newIface
|
|
return newIface, true
|
|
}
|
|
|
|
w := func(s string) {
|
|
_, _ = buf.WriteString(s)
|
|
_ = buf.WriteByte('\n')
|
|
}
|
|
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
upForChange := currentIfaceName == "" ||
|
|
(currentIfaceName != "" && !strings.Contains(line, currentIfaceName)) ||
|
|
index == 0
|
|
startDetected := len(strings.Fields(line)) > 1 &&
|
|
(strings.HasPrefix(line, "auto") ||
|
|
strings.HasPrefix(line, "allow-") ||
|
|
strings.HasPrefix(line, "iface"))
|
|
|
|
switch {
|
|
case line == "", strings.HasPrefix(line, "#"):
|
|
continue
|
|
case upForChange && startDetected:
|
|
newName := strings.Fields(line)[1]
|
|
if ifa, ok := flush(newName); ok {
|
|
currentIfaceName = ifa.Name
|
|
index++
|
|
}
|
|
w(line)
|
|
continue
|
|
default:
|
|
w(line)
|
|
}
|
|
}
|
|
|
|
if len(buf.Bytes()) > 0 {
|
|
flush("unknown")
|
|
}
|
|
var multiErr error
|
|
for _, err := range p.Errs {
|
|
switch {
|
|
case err == nil:
|
|
continue
|
|
case multiErr == nil:
|
|
multiErr = err
|
|
default:
|
|
multiErr = fmt.Errorf("%w, %w", multiErr, err)
|
|
}
|
|
}
|
|
return p.Interfaces, multiErr
|
|
}
|