1
0
mirror of https://github.com/lxc/distrobuilder.git synced 2026-02-05 06:45:19 +01:00
Files
distrobuilder/sources/slackware-http.go
Stéphane Graber 57091a0e63 Fix golang-ci reported issues
Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
2025-04-02 14:37:13 -04:00

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
}