github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/ldd/ldd_darwin.go (about)

     1  // Copyright 2021 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build darwin
     6  // +build darwin
     7  
     8  // ldd returns none of the library dependencies of an executable.
     9  //
    10  // On many Unix kernels, the kernel ABI is stable. On OSX, the stability
    11  // is held in the library interface; the kernel ABI is explicitly not
    12  // stable. The ldd package on OSX will only return the files passed to it.
    13  // It will continue to resolve symbolic links.
    14  package ldd
    15  
    16  import (
    17  	"fmt"
    18  	"os"
    19  	"path/filepath"
    20  )
    21  
    22  // Follow starts at a pathname and adds it
    23  // to a map if it is not there.
    24  // If the pathname is a symlink, indicated by the Readlink
    25  // succeeding, links repeats and continues
    26  // for as long as the name is not found in the map.
    27  func follow(l string, names map[string]*FileInfo) error {
    28  	for {
    29  		if names[l] != nil {
    30  			return nil
    31  		}
    32  		i, err := os.Lstat(l)
    33  		if err != nil {
    34  			return fmt.Errorf("%v", err)
    35  		}
    36  
    37  		names[l] = &FileInfo{FullName: l, FileInfo: i}
    38  		if i.Mode().IsRegular() {
    39  			return nil
    40  		}
    41  		// If it's a symlink, the read works; if not, it fails.
    42  		// we can skip testing the type, since we still have to
    43  		// handle any error if it's a link.
    44  		next, err := os.Readlink(l)
    45  		if err != nil {
    46  			return err
    47  		}
    48  		// It may be a relative link, so we need to
    49  		// make it abs.
    50  		if filepath.IsAbs(next) {
    51  			l = next
    52  			continue
    53  		}
    54  		l = filepath.Join(filepath.Dir(l), next)
    55  	}
    56  }
    57  
    58  // Ldd returns the list of files passed to it, and resolves all symbolic
    59  // links, returning them as well.
    60  //
    61  // It's not an error for a file to not be an ELF.
    62  func Ldd(names []string) ([]*FileInfo, error) {
    63  	var (
    64  		list = make(map[string]*FileInfo)
    65  		libs []*FileInfo
    66  	)
    67  	for _, n := range names {
    68  		if err := follow(n, list); err != nil {
    69  			return nil, err
    70  		}
    71  	}
    72  	for i := range list {
    73  		libs = append(libs, list[i])
    74  	}
    75  
    76  	return libs, nil
    77  }
    78  
    79  type FileInfo struct {
    80  	FullName string
    81  	os.FileInfo
    82  }
    83  
    84  // List returns the dependency file paths of files in names.
    85  func List(names []string) ([]string, error) {
    86  	var list []string
    87  	l, err := Ldd(names)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	for i := range l {
    92  		list = append(list, l[i].FullName)
    93  	}
    94  	return list, nil
    95  }