Skip to content

Commit

Permalink
prepare 3.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
zeriyoshi committed Jul 25, 2024
1 parent fef4d9d commit b948efc
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 136 deletions.
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ARG _DEB_VERSION="12"
ARG PLATFORM="linux/arm64/v8"

ARG BASE="debian:${_DEB_VERSION}"
ARG BASE_PKGS="php"
ARG BASE_PKGS="php binutils"
ARG BASE_BINS="php"
ARG BASE_PKG_INSTALL_CMD="apt-get update && apt-get install -y"

Expand All @@ -17,7 +17,8 @@ FROM --platform="${PLATFORM}" ${GOLANG} AS golang

COPY "./" "/build"

RUN cd "/build" \
RUN apt-get update && apt-get install -y "binutils" \
&& cd "/build" \
&& go get \
&& go build -o "/usr/local/bin/dependency_resolve" . \
&& strip --strip-all "/usr/local/bin/dependency_resolve" \
Expand All @@ -35,7 +36,7 @@ COPY --from=golang "/usr/local/bin/dependency_resolve" "/usr/local/bin/dependenc

RUN /bin/sh -c "${BASE_PKG_INSTALL_CMD} ${BASE_PKGS}" \
&& /usr/local/bin/dependency_resolve \
$(echo "${BASE_BINS}" | xargs which) \
$(echo ${BASE_BINS} | xargs which) \
| xargs -I {} sh -c 'mkdir -p /rootfs/$(dirname "{}") && cp -apP "{}" "/rootfs/{}" && (strip --strip-all "/rootfs/{}" || true)'

FROM --platform="${PLATFORM}" ${TARGET} AS target
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ RUN cd "/build" \
&& strip --strip-all "/usr/local/bin/dependency_resolve"
&& cd -
COPY --from=golang "/usr/local/bin/dependency_resolve" "/usr/local/bin/dependency_resolve"
RUN apt-get update && apt-get install -y "php"
RUN apt-get update && apt-get install -y "binutils" "php"
RUN /usr/local/bin/dependency_resolve "$(which "php")" | xargs -I {} sh -c 'mkdir -p /rootfs/$(dirname "{}") && cp -apP "{}" "/rootfs/{}" && (strip --strip-all "/rootfs/{}" || true)'

FROM gcr.io/distroless/base-nossl-debian12:latest
Expand Down
174 changes: 42 additions & 132 deletions dependency_resolve.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
//go:build linux

package main

import (
"bufio"
"debug/elf"
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"slices"
"strings"
"sync"

"github.com/u-root/u-root/pkg/ldd"
)

type smartDict struct {
Expand All @@ -22,16 +23,11 @@ func newSmartDict(allocSize int) *smartDict {
return &smartDict{m: make(map[string]struct{}, allocSize)}
}

func (s *smartDict) exists(key string) bool {
s.mu.RLock()
_, exists := s.m[key]
s.mu.RUnlock()
return exists
}

func (s *smartDict) append(key string) {
func (s *smartDict) appendAll(keys ...string) {
s.mu.Lock()
s.m[key] = struct{}{}
for _, key := range keys {
s.m[key] = struct{}{}
}
s.mu.Unlock()
}

Expand All @@ -46,31 +42,20 @@ func (s *smartDict) keys() []string {
}

func version() {
fmt.Println("3.0.1")
fmt.Println("3.1.0")
}

func usage() {
fmt.Println("Usage: dependency_resolve <file1> <file2> ...")
}

func prepareExec(args []string) {
if runtime.GOOS != "linux" {
log.Fatalln("dependency_resolve supports Linux only.")
os.Exit(1)
}

if len(args) < 2 {
usage()
os.Exit(2)
}
}

func checkBins(bins []string) []string {
for _, v := range bins {
if !filepath.IsAbs(v) {
log.Fatalf("Arguments must be absolute path: %s\n", v)
}

// allow symlink
fi, err := os.Stat(v)
if err != nil {
log.Fatalf("os.Stat error: %v\n", err)
Expand All @@ -88,117 +73,51 @@ func checkBins(bins []string) []string {
return bins
}

func depResolve(wg *sync.WaitGroup, sd *smartDict, ldpaths []string, path string) {
if sd.exists(path) {
return
}

wg.Add(1)
go func() {
defer wg.Done()

fi, err := os.Lstat(path)
if err != nil {
log.Fatalf("os.Lstat failed: %s, error: %v", path, err)
}

sd.append(path)
if fi.Mode()&os.ModeSymlink != 0 {
// symlink
lp, err := os.Readlink(path)
if err != nil {
log.Fatalf("os.Readlink failed: %s, error: %v", path, err)
}

if !filepath.IsAbs(lp) {
lp = filepath.Join(filepath.Dir(path), lp)
}
func depResolves(sd *smartDict, bins ...string) {
var wg sync.WaitGroup

depResolve(wg, sd, ldpaths, lp)
} else {
f, err := elf.Open(path)
if err != nil {
// Not ELF file
return
}
defer f.Close()
sd.appendAll(bins...)
for _, bin := range bins {
wg.Add(1)
go func(bin string, sd *smartDict, wg *sync.WaitGroup) {
defer wg.Done()

libs, err := f.ImportedLibraries()
fi, err := os.Lstat(bin)
if err != nil {
log.Fatalf("elf.ImportedLibraries() failed: %s, error: %v", path, err)
log.Fatalf("os.Lstat failed: %s (%v)\n", bin, err)
}

for _, lib := range libs {
wg.Add(1)
go func() {
defer wg.Done()
for _, ldpath := range ldpaths {
fpath := filepath.Join(ldpath, lib)
if _, err := os.Stat(fpath); err == nil {
depResolve(wg, sd, ldpaths, fpath)
break
}
}
}()
}
}
}()
}

func readLdSoConf(file string, paths *[]string) error {
fp, err := os.Open(file)
if err != nil {
return err
}
defer fp.Close()

scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}

if strings.HasPrefix(line, "include ") {
matches, err := filepath.Glob(strings.TrimSpace(strings.TrimPrefix(line, "include ")))
if err != nil {
return err
}
for _, match := range matches {
if err := readLdSoConf(match, paths); err != nil {
return err
if fi.Mode()&os.ModeSymlink != 0 {
// symlink
lp, err := os.Readlink(bin)
if err != nil {
log.Fatalf("os.Readlink failed: %s (%v)\n", bin, err)
}
}
} else {
*paths = append(*paths, line)
}
}

return scanner.Err()
}
if !filepath.IsAbs(bin) {
lp = filepath.Join(filepath.Dir(bin), lp)
}

func getDefaultLdPaths() ([]string, error) {
var paths []string
depResolves(sd, lp)
} else if _, err := elf.Open(bin); err == nil {
// bin
deps, err := ldd.FList(bin)
if err != nil {
log.Fatalf("ldd.FList failed: %s (%v)\n", bin, err)
}

for _, v := range []string{"/etc/ld.so.conf"} {
if _, err := os.Stat(v); err == nil {
if err := readLdSoConf(v, &paths); err != nil {
return nil, err
sd.appendAll(deps...)
}
}
}(bin, sd, &wg)
}

for _, v := range []string{"/lib", "/usr/lib"} {
if d, err := os.Stat(v); err == nil && d.IsDir() {
paths = append(paths, v)
}
}

return paths, nil
wg.Wait()
}

func main() {
prepareExec(os.Args)
if len(os.Args) < 2 {
usage()
os.Exit(2)
}

switch os.Args[1] {
case "-h", "--help":
Expand All @@ -211,16 +130,7 @@ func main() {

bins := checkBins(os.Args[1:])
sd := newSmartDict(len(bins))
ldpaths, err := getDefaultLdPaths()
if err != nil {
log.Fatalf("Failed get LDPATH: %v", err)
}

var wg sync.WaitGroup
for _, bin := range bins {
depResolve(&wg, sd, ldpaths, bin)
}
wg.Wait()
depResolves(sd, bins...)

libs := sd.keys()
slices.Sort(libs)
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/distroless-php/dependency_resolve

go 1.22.5

require github.com/u-root/u-root v0.14.0 // indirect
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg=
github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1WMluqE=

0 comments on commit b948efc

Please sign in to comment.