File: apt.go

package info (click to toggle)
adequate 0.17.6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 488 kB
  • sloc: python: 254; makefile: 111; sh: 75; ansic: 29
file content (134 lines) | stat: -rw-r--r-- 3,105 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// This file is part of the adequate Debian-native package, and is available
// under the Expat license. For the full terms please see debian/copyright.

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"syscall"
)

const pendingPath = "/var/lib/adequate/pending"

func aptHookReader() *bufio.Reader {
	return bufio.NewReader(os.Stdin)
}

func aptHookIsEnabled(reader *bufio.Reader) bool {
	var enabled, defined bool

loop:
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			// We're only supposed to read the configuration
			// section, which ends with an empty line, so we
			// shouldn't hit EOF.
			if err == io.EOF {
				log.Fatal("Found EOF while reading apt configuration section.")
			}
			log.Fatal("Read error: ", err)
		}

		switch line {
		case "Adequate::Enabled=true\n":
			enabled = true
			defined = true
		case "Adequate::Enabled=false\n":
			enabled = false
			defined = true
		case "\n":
			break loop
		}
	}

	if !defined {
		log.Println("apt hook is not enabled")
		return false
	}
	return enabled
}

func readPkgs(reader *bufio.Reader) []string {
	var pkgs []string

	for {
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			log.Fatal("Read error: ", err)
		}

		if line == "" || err == io.EOF {
			break
		}
		// We're looking for files with this structure:
		//	pkg, fromVer, operator, toVer, debFilePath
		// Sample line:
		// libparted-fs-resize0 3.5-3 = 3.5-3 /var/cache/apt/archives/libparted-fs-resize0_3.5-3_amd64.deb
		fields := strings.Fields(line)
		if n := len(fields); n != 5 || !strings.HasSuffix(line, ".deb\n") {
			continue
		}
		pkgs = append(pkgs, fields[0])
	}
	return pkgs
}

type pendingHandler struct {
	fi *os.File
}

func newPendingHandler() (*pendingHandler, error) {
	fi, err := os.OpenFile(pendingPath, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return nil, fmt.Errorf("%s: %w", pendingPath, err)
	}
	if err := syscall.Flock(int(fi.Fd()), syscall.LOCK_EX); err != nil {
		return nil, fmt.Errorf("%s: %w", pendingPath, err)
	}
	return &pendingHandler{
		fi: fi,
	}, nil
}

func (ph *pendingHandler) read() ([]string, error) {
	if _, err := ph.fi.Seek(0, 0); err != nil {
		fmt.Errorf("failed to seek %s: %w", pendingPath, err)
	}
	return readLines(ph.fi)
}

func (ph *pendingHandler) truncatePendingOrDie() {
	ph.writePendingOrDie(nil)
}

func (ph *pendingHandler) writePendingOrDie(pkgs []string) {
	if ph.fi == nil {
		log.Fatal("writePendingOrDie() called with nil file handler")
	}
	if err := ph.fi.Truncate(0); err != nil {
		log.Fatalf("Failed to truncate %s: %v", pendingPath, err)
	}
	if _, err := ph.fi.Seek(0, 0); err != nil {
		log.Fatalf("Failed to seek %s: %v", pendingPath, err)
	}

	for _, pkg := range pkgs {
		if _, err := ph.fi.WriteString(pkg + "\n"); err != nil {
			log.Fatalf("Failed to write %s: %v", pendingPath, err)
		}
	}

}

func (ph *pendingHandler) cleanupOrDie() error {
	if err := syscall.Flock(int(ph.fi.Fd()), syscall.LOCK_UN); err != nil {
		log.Fatalf("Failed to release file lock for %s: %v", pendingPath, err)
	}
	return ph.fi.Close()
}