Skip to content

Commit

Permalink
Merge pull request #766 from slapcat/main
Browse files Browse the repository at this point in the history
Add support for slackware
  • Loading branch information
stgraber authored Sep 1, 2023
2 parents f77300b + d446a23 commit e302a95
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/reference/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Valid package manager are:
* `opkg`
* `pacman`
* `portage`
* `slackpkg`
* `xbps`
* `yum`
* `zypper`
Expand Down
1 change: 1 addition & 0 deletions managers/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ var managers = map[string]func() manager{
"opkg": func() manager { return &opkg{} },
"pacman": func() manager { return &pacman{} },
"portage": func() manager { return &portage{} },
"slackpkg": func() manager { return &slackpkg{} },
"xbps": func() manager { return &xbps{} },
"yum": func() manager { return &yum{} },
"zypper": func() manager { return &zypper{} },
Expand Down
38 changes: 38 additions & 0 deletions managers/slackpkg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package managers

type slackpkg struct {
common
}

func (m *slackpkg) load() error {
m.commands = managerCommands{
install: "slackpkg",
remove: "slackpkg",
refresh: "slackpkg",
update: "true",
clean: "true",
}

m.flags = managerFlags{
global: []string{
"-batch=on", "-default_answer=y",
},
install: []string{
"install",
},
remove: []string{
"remove",
},
refresh: []string{
"update",
},
update: []string{
"upgrade-all",
},
clean: []string{
"clean-system",
},
}

return nil
}
3 changes: 3 additions & 0 deletions shared/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ func (d *Definition) Validate() error {
"rootfs-http",
"rockylinux-http",
"vyos-http",
"slackware-http",
}

if !shared.StringInSlice(strings.TrimSpace(d.Source.Downloader), validDownloaders) {
Expand All @@ -400,6 +401,7 @@ func (d *Definition) Validate() error {
"xbps",
"zypper",
"luet",
"slackpkg",
}

if !shared.StringInSlice(strings.TrimSpace(d.Packages.Manager), validManagers) {
Expand Down Expand Up @@ -464,6 +466,7 @@ func (d *Definition) Validate() error {
"plamolinux",
"voidlinux",
"funtoo",
"slackware",
}

architectureMap := strings.TrimSpace(d.Mappings.ArchitectureMap)
Expand Down
6 changes: 6 additions & 0 deletions shared/osarch.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ var funtooArchitectureNames = map[int]string{
osarch.ARCH_64BIT_ARMV8_LITTLE_ENDIAN: "arm64_generic",
}

var slackwareArchitectureNames = map[int]string{
osarch.ARCH_32BIT_INTEL_X86: "i586",
osarch.ARCH_64BIT_INTEL_X86: "x86_64",
}

var distroArchitecture = map[string]map[int]string{
"alpinelinux": alpineLinuxArchitectureNames,
"altlinux": altLinuxArchitectureNames,
Expand All @@ -75,6 +80,7 @@ var distroArchitecture = map[string]map[int]string{
"plamolinux": plamoLinuxArchitectureNames,
"voidlinux": voidLinuxArchitectureNames,
"funtoo": funtooArchitectureNames,
"slackware": slackwareArchitectureNames,
}

// GetArch returns the correct architecture name used by the specified
Expand Down
176 changes: 176 additions & 0 deletions sources/slackware-http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package sources

import (
"errors"
"fmt"
"net/url"
"path"
"path/filepath"
"strings"

lxd "github.com/canonical/lxd/shared"
"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 !((lxd.StringInSlice(pkgName, requiredPkgs)) || (lxd.StringInSlice(twoPkgName, requiredPkgs))) {
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
}
1 change: 1 addition & 0 deletions sources/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var downloaders = map[string]func() downloader{
"ubuntu-http": func() downloader { return &ubuntu{} },
"voidlinux-http": func() downloader { return &voidlinux{} },
"vyos-http": func() downloader { return &vyos{} },
"slackware-http": func() downloader { return &slackware{} },
}

// Load loads and initializes a downloader.
Expand Down

0 comments on commit e302a95

Please sign in to comment.