From 053e07c3190c823f1c24f2c659975cdc06559885 Mon Sep 17 00:00:00 2001 From: mappu Date: Sun, 30 Jun 2024 13:47:29 +1200 Subject: [PATCH] debconf: implement dat file parser --- debconf/debconf.go | 92 +++++++++++++++++++++++++++++++++++++++++ debconf/debconf_test.go | 30 ++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 debconf/debconf.go create mode 100644 debconf/debconf_test.go diff --git a/debconf/debconf.go b/debconf/debconf.go new file mode 100644 index 0000000..cd619b0 --- /dev/null +++ b/debconf/debconf.go @@ -0,0 +1,92 @@ +package debconf + +import ( + "bufio" + "fmt" + "io" + "strings" +) + +const ( + DefaultConfigDat = `/var/cache/debconf/config.dat` + DefaultPasswordsDat = `/var/cache/debconf/passwords.dat` + DefaultTemplatesDat = `/var/cache/debconf/templates.dat` +) + +type Entry struct { + Name string + Properties [][2]string +} + +type Database struct { + Entries []Entry + AllColumnNames []string +} + +func Parse(r io.Reader) (*Database, error) { + sc := bufio.NewScanner(r) + + var entries []Entry + var wip Entry + var linenum int = 0 + + knownColumnNames := map[string]struct{}{ + "Name": struct{}{}, + } + var discoveredColumns []string + + for sc.Scan() { + linenum++ + line := sc.Text() + + if line == "" { + if wip.Name != "" { + entries = append(entries, wip) + wip = Entry{} + } + continue + } + + if line[0] == ' ' { + // continuation of last text entry + if len(wip.Properties) == 0 { + return nil, fmt.Errorf("Continuation of nonexistent entry on line %d", linenum) + } + + wip.Properties[len(wip.Properties)-1][1] += line[1:] + + } else { + // New pair on current element + key, rest, ok := strings.Cut(line, `:`) + if !ok { + return nil, fmt.Errorf("Missing : on line %d", linenum) + } + + if _, ok := knownColumnNames[key]; !ok { + knownColumnNames[key] = struct{}{} + discoveredColumns = append(discoveredColumns, key) + } + + if key == `Name` { + wip.Name = rest + } else { + wip.Properties = append(wip.Properties, [2]string{key, rest}) + } + + } + + } + + if sc.Err() != nil { + return nil, sc.Err() + } + + if wip.Name != "" { + entries = append(entries, wip) + } + + return &Database{ + Entries: entries, + AllColumnNames: discoveredColumns, + }, nil +} diff --git a/debconf/debconf_test.go b/debconf/debconf_test.go new file mode 100644 index 0000000..53670e8 --- /dev/null +++ b/debconf/debconf_test.go @@ -0,0 +1,30 @@ +package debconf + +import ( + "os" + "testing" +) + +func TestDebconfParse(t *testing.T) { + src, err := os.Open(DefaultConfigDat) + if err != nil { + if os.IsNotExist(err) { + t.Skip(err) + } + t.Fatal(err) + } + defer src.Close() + + db, err := Parse(src) + if err != nil { + t.Fatalf("Parse: %v", err) + } + + if len(db.Entries) == 0 { + t.Errorf("expected >0 entries, got %v", len(db.Entries)) + } + + if len(db.AllColumnNames) == 0 { + t.Errorf("expected >0 column names, got %v", len(db.AllColumnNames)) + } +}