mirror of
https://github.com/lxc/distrobuilder.git
synced 2026-02-05 15:46:17 +01:00
178 lines
5.6 KiB
Go
178 lines
5.6 KiB
Go
package sources
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"path"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/antchfx/htmlquery"
|
|
|
|
"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
|
|
switch s.definition.Image.ArchitectureMapped {
|
|
case "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)
|
|
case "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)
|
|
default:
|
|
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
|
|
}
|