-
Notifications
You must be signed in to change notification settings - Fork 161
/
slackware-http.go
176 lines (141 loc) · 5.61 KB
/
slackware-http.go
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package sources
import (
"errors"
"fmt"
"net/url"
"path"
"path/filepath"
"slices"
"strings"
"gopkg.in/antchfx/htmlquery.v1"
"github.com/lxc/distrobuilder/shared"
)
type slackware struct {
common
}
// Run downloads Slackware Linux.
func (s *slackware) Run() error {
u, err := url.Parse(s.definition.Source.URL)
if err != nil {
return fmt.Errorf("Failed to parse %q: %w", s.definition.Source.URL, err)
}
mirrorPath := ""
slackpkgPath := ""
// set mirror path based on architecture
if s.definition.Image.ArchitectureMapped == "i586" {
mirrorPath = path.Join(u.Path, fmt.Sprintf("slackware-%s", s.definition.Image.Release), "slackware")
slackpkgPath = s.definition.Source.URL + fmt.Sprintf("slackware-%s", s.definition.Image.Release)
} else if s.definition.Image.ArchitectureMapped == "x86_64" {
mirrorPath = path.Join(u.Path, fmt.Sprintf("slackware64-%s", s.definition.Image.Release), "slackware64")
slackpkgPath = s.definition.Source.URL + fmt.Sprintf("slackware64-%s", s.definition.Image.Release)
} else {
return fmt.Errorf("Invalid architecture: %s", s.definition.Image.Architecture)
}
// base software packages and libraries
paths := []string{path.Join(mirrorPath, "a")}
// additional required libraries
paths = append(paths, path.Join(mirrorPath, "ap"), path.Join(mirrorPath, "d"), path.Join(mirrorPath, "l"),
path.Join(mirrorPath, "n"))
requiredPkgs := []string{"sysvinit", "sysvinit-scripts", "aaa_base", "aaa_elflibs", "aaa_libraries", "coreutils", "glibc-solibs", "aaa_glibc-solibs", "aaa_terminfo", "pam", "cracklib", "libpwquality", "e2fsprogs", "nvi", "pkgtools", "shadow", "tar", "xz", "bash", "etc", "gzip", "pcre2", "libpsl", "wget", "gnupg", "elvis", "slackpkg", "ncurses", "bin", "bzip2", "grep", "acl", "pcre", "gmp", "attr", "sed", "dialog", "file", "gawk", "time", "gettext", "libcgroup", "patch", "sysfsutils", "time", "tree", "utempter", "which", "util-linux", "elogind", "libseccomp", "mpfr", "libunistring", "diffutils", "procps", "findutils", "iproute2", "dhcpcd", "openssl", "perl", "ca-certificates", "inetd", "iputils", "libmnl", "network-scripts", "libaio", "glibc", "nano", "hostname"}
var pkgDir string
for _, p := range paths {
u.Path = p
pkgDir, err = s.downloadFiles(s.definition.Image, u.String(), requiredPkgs)
if err != nil {
return fmt.Errorf("Failed to download packages: %w", err)
}
}
// find package tools
matches, err := filepath.Glob(filepath.Join(pkgDir, "pkgtools-*.t*z"))
if err != nil {
return fmt.Errorf("Failed to match pattern: %w", err)
}
err = shared.RunCommand(s.ctx, nil, nil, "tar", "-pxf", matches[0], "-C", pkgDir, "sbin/")
if err != nil {
return fmt.Errorf("Failed to unpack %q: %w", matches[0], err)
}
rootfsDirAbs, err := filepath.Abs(s.rootfsDir)
if err != nil {
return fmt.Errorf("Failed to get absolute path: %w", err)
}
// build rootfs
err = shared.RunScript(s.ctx, fmt.Sprintf(`#!/bin/sh
set -eux
# Input variables
PKG_DIR="%s"
ROOTFS_DIR="%s"
# Environment
export LC_ALL="C"
export LANG="C"
# Don't override PATH
sed -i "/^export PATH/d" ${PKG_DIR}/sbin/installpkg*
# Install all packages
# not compatible with versions < 13.37
for pkg in $(ls -cr ${PKG_DIR}/*.t*z); do
# Prevent install script for sysvinit from trying to run /sbin/init
if (echo ${pkg} | grep -E 'sysvinit-[0-9]') ; then
mkdir -p ${PKG_DIR}/sysvinit && cd ${PKG_DIR}/sysvinit
tar -xf ${pkg}
sed -i 's@/sbin/init@#/sbin/init@' install/doinst.sh
tar -cJf ${pkg} *
${PKG_DIR}/sbin/installpkg --terse --root ${ROOTFS_DIR} ${pkg}
cd -
else
${PKG_DIR}/sbin/installpkg --terse --root ${ROOTFS_DIR} ${pkg}
fi
done
# Disable kernel/sys modifications
sed -i 's@/bin/dmesg@#/bin/dmesg@g' ${ROOTFS_DIR}/etc/rc.d/rc.M
sed -i 's@/sbin/modprobe@echo@g' ${ROOTFS_DIR}/etc/rc.d/rc.inet1
if [ -f ${ROOTFS_DIR}/etc/rc.d/rc.elogind ]; then
sed -i 's@cd /sys/fs/cgroup;@@g' ${ROOTFS_DIR}/etc/rc.d/rc.elogind
fi
# Enable networking on eth0
sed -i 's/USE_DHCP\[0\]=""/USE_DHCP\[0\]="yes"/' ${ROOTFS_DIR}/etc/rc.d/rc.inet1.conf
sed -i 's/USE_DHCP6\[0\]=""/USE_DHCP6\[0\]="yes"/' ${ROOTFS_DIR}/etc/rc.d/rc.inet1.conf
# Some services expect fstab
touch ${ROOTFS_DIR}/etc/fstab
# Add mirror to slackpkg
mkdir -p ${ROOTFS_DIR}/etc/slackpkg
echo "%s" > ${ROOTFS_DIR}/etc/slackpkg/mirrors
`, pkgDir, rootfsDirAbs, slackpkgPath))
if err != nil {
return fmt.Errorf("Failed to run script: %w", err)
}
return nil
}
func (s *slackware) downloadFiles(def shared.DefinitionImage, URL string, requiredPkgs []string) (string, error) {
doc, err := htmlquery.LoadURL(URL)
if err != nil {
return "", fmt.Errorf("Failed to load URL %q: %w", URL, err)
}
if doc == nil {
return "", errors.New("Empty HTML document")
}
nodes := htmlquery.Find(doc, `//a/@href`)
var dir string
for _, n := range nodes {
target := htmlquery.InnerText(n)
if strings.HasSuffix(target, ".txz") || strings.HasSuffix(target, ".tgz") {
pkgName := strings.Split(target, "-")[0]
twoPkgName := strings.Split(target, "-")[0] + "-" + strings.Split(target, "-")[1]
if !((slices.Contains(requiredPkgs, pkgName)) || (slices.Contains(requiredPkgs, twoPkgName))) {
continue
}
// package
dir, err = s.DownloadHash(def, fmt.Sprintf("%s/%s", URL, target), "", nil)
if err != nil {
return "", fmt.Errorf("Failed to download %q: %w", fmt.Sprintf("%s/%s", URL, target), err)
}
} else if strings.HasSuffix(target, ".txz/") || strings.HasSuffix(target, ".tgz/") {
// directory
u, err := url.Parse(URL)
if err != nil {
return "", fmt.Errorf("Failed to parse %q: %w", URL, err)
}
u.Path = path.Join(u.Path, target)
return s.downloadFiles(def, u.String(), requiredPkgs)
}
}
return dir, nil
}