Portable bináris függőségeit tartalmazó csomagok

Adott egy futtatható bináris, amit nem csomagkezelőből telepítettünk. Nem akar elindulni a hiányzó függőségek miatt, de mivel nem csomagból van így a szükséges csomagokat max. úgy lehet összeszedni, hogy objdump-pal kiolvassuk a libeket, aztán egyesével megnézetjük a csomagkezelővel, hogy melyik csomag tartalmazza azt. Ezt én most automatizáltam magamnak (Debian-ra), akinek kell viheti, átírhatja másik csomagkezelőre, mittudomén...

#!/bin/sh

if [ ! -f "$1" ]; then
	echo "Usage: lsdeppkg <ELF-FILE>"
	exit
fi

DISTRO=`cat /etc/*-release | awk -F '"' '/NAME/ {print $2; exit}'`
TMP=$(mktemp /tmp/deplst-XXXXXX)
PKGS=""
objdump -p "$1" | grep "NEEDED" > "$TMP"
while IFS= read -r file; do
	file=`echo "$file" | awk -F ' ' '{print $2}'`
	if [ "$DISTRO" == "Arch Linux" ]; then
		PKG=`pacman -Fsq "$file"`
		if [ "$PKG" != "" ]; then
			PKG=`echo "$PKG" | head -1`
		fi
	else
		PKG=`dpkg -S "$file" 2>/dev/null`
		if [ "$PKG" != "" ]; then
			PKG=`echo "$PKG" | cut -f1 -d":"`
		fi
	fi
	if [ "$PKG" == "" ]; then
		(>&2 echo "$file: No match.")
	else
		PKGS="$PKGS$PKG\n"
	fi
done < "$TMP"
rm "$TMP"
echo "Packages:"
echo "$PKGS" | sort | uniq | tr '\n' ' '
echo ""

A script az összeszedett csomagokat a végén egybe köpi ki (szóközökkel elválasztva), akár át is lehet dobni a csomagkezelőnek; az olyan libeket viszont menet közben írja ki az stderr-re, amikhez nem talált csomagot.

Építő jellegű javaslatokat szívesen fogadok egyszerűsítésre, optimalizációra, vagy akármi másra.

Sz*rk: zolk3ri kolléga már küldött is egy patchet, amiben a temp fájl nevét mktemp-pel állítja elő és az Arch pacman-jét is támogatja.

Hozzászólások

en az ldd-t szoktam hasznalni...

--
t-systems-es it architect allast keres. Jelige: csak webshopot ne kelljen...

Nem biztos, hogy az jó ötlet, két okból is: Egyrészt az ldd hajlamos elindítani a programot, hogy kiderítse a függőségeit (ami egy harmadik féltől származó programnál nem feltétlen jó ötlet), másrészt az ldd rekurzívan vizsgálja a függőségeket, azaz nem csak a program által linkelt objektumokat listázza, hanem azokat is, amik már az SO-kban vannak linkelve, ez pedig azzal fog járni, hogy a csomagkezelőnek egy jóval nagyobb listában kell keresnie, hogy melyik csomag tartalmazza az adott libet, ami megsokszorozza a futásidőt, ráadásul értelmetlen, hiszen ha a program által linkelt objektumok csomagjait megkaptuk, akkor azok a csomagok úgyis magukkal fogják húzni a függőségeiket és velük együtt azokat a libeket, amikre a a program által linkelt libek linkelnek.

A megfogalmazás talán pongyola és szakmaiatlan volt, de nagyjából erről van szó:

#man ldd

---

ldd kiírja a parancssorban megadott program futtatásához szükséges
megosztott könyvtárakat.

Az a.out programoknál az ldd egyszerűen egy fork és egy exec
segítségével az argc-nek nullát megadva elindítja a programot. Az a.out
dinamikus linkere, az ld.so, amely normálisan betölti a megosztott
könyvtárakat, észreveszi ezt a speciális indítást, és kiírja a
szükséges könyvtárakat.

ELF programoknál az ldd egy fork és egy exec segítségével elindítja a
programot, és beállít egy megfelelő környezeti változót. Az ELF
dinamikus linker, az ld-linux.so, amely normálisan a megosztott
könyvtárakat betölti, észreveszi ezt a speciális esetet és kiírja a
futtatáshoz szükséges könyvtárak listáját.

Gyakran teszel fel ismeretlen forrasbol szarmazo binarist?

Ha egy program nincs benne a repoban (ez azert Debianban eleg nagy, marmint a repo), akkor jon a forrasbol forditas. Az meg amugy is elarulja, hogy milyen fuggosegei vannak (mindenfele -dev csomagot fel kell rakni, aztan hajra).

Ha meg zart forrasu, akkor vagy csomagot adnak, vagy valami installer scriptet, ami ezeket elrendezi idealis esetben.

--
Any A.I. smart enough to pass a Turing test is smart enough to know to fail it. -Ian McDonald

Nem rosszindulat, csak gyakran bele lehet olyasmibe futni,hogy valamit elkészítenek RHEL/CentOS vonalra, aztán de alapú rendszerre "azérisfelszögeljükmertazrpmyumfúj" alapon csak azért is felszögeljük - és ekkor szokott előkerülni az, hogy oké, de az x, y, z... akármi függőséget honnan, melyik csomagból lehet fellapátolni.

Aki meg targézéből vagy más csomagkezelőn kívüli módon rak fel sz@rul-vagy-sehogy dokumentált olyan motyót, aminek így kell megkeresni a függőségeit, nos, az magára vessen...

Melyik gyártó az, ami ad-hoc buildel valamit úgy, hogy se CentOS/RHEL se Debian/Ubuntu vonalon nincs kijelölt támogatott OS, és a lomjának perverz, nem dokumentált függőségei vannak? Nehezen hihető, hogy csak úgy kiböffent valaki egy binárist Linuxra, nulla leírással a használat feltételeiről, függőségeiről...


#!/bin/sh

if [ ! -f "$1" ]; then
echo "Usage: lsdeppkg "
exit
fi

DISTRO=`cat /etc/*-release | awk -F '"' '/NAME/ {print $2; exit}'`
TMP=`mktemp /tmp/deplst-XXXXXX`
PKGS=""
objdump -p "$1" | grep "NEEDED" > "$TMP"
while IFS= read -r file; do
file=`echo "$file" | awk -F ' ' '{print $2}'`
if [ "$DISTRO" == "Arch Linux" ]; then
PKG=`pacman -Fsq "$file" 2>/dev/null | head -1`
else
PKG=`dpkg -S "$file" 2>/dev/null | cut -f1 -d":"`
fi
if [ $? -eq 0 ]; then
if [ "$PKGS" == "" ]; then
PKGS="$PKG"
else
PKGS="$PKGS\n$PKG"
fi
else
(>&2 echo "$file: No match.")
fi
done < "$TMP"
rm "$TMP"
echo "Packages:"
echo -e "$PKGS" | sort | uniq | tr '\n' ' '
echo ""

Igen, igen, tudom, úgy tűnik, hogy a code tag nem elég a helyes formázáshoz.
Tudna valaki segíteni? 8 éve vagyok itt, de még egyszer sem szúrtam be kódot. :P

Igen, gondoltam, de már nem tudtam módosítani. :D

Mindegy, a lényeg gondolom átment, hogy jobb ilyen esetben mktemp-et használni, hogy ne okozzon problémát a script többszöri párhuzamos futtatása, például ha több user használná egy időben, vagy több binárison akarod futtatni egyszerre, aminek persze a valószínűsége elhanyagolható.

Arch Linux támogatást kiegészítésképpen adtam hozzá, hátha valakinek szüksége van rá.

Feltételeztem, hogy a cut -f1 -d":" azért kell, mert a dpkg outputja megköveteli, ezért ezt beraktam a dpkg-vel azonos sorba, tehát még egyszer futtatni felesleges, de azért jó lenne, ha tesztelnéd. :D

Amit még változtattam az a következő:


if [ "$PKGS" == "" ]; then
    PKGS="$PKG"
else
    PKGS="$PKGS\n$PKG"
fi

ami csak arra jó, hogy a $PKGS elején ne legyen egy felesleges \n majd később ebből egy szóköz.

Hopsz, az most esik le, hogy az úgy nem jó, sem a dpkg, sem a pacman sorában sem, hiszen ha átadod a csövön keresztül a végeredményt egy másik programnak, akkor utána a $?-ben nem a csomagkezelő, hanem a másik program, a cut és a head visszatérési értékei lesznek... Az nem véletlen volt különválasztva. Beraktam, hogy miután megvan a végeredmény, a kapott szöveget a disztrónak megfelelően dolgozza fel. Ha van jobb ötleted, ne tartsd magadban.

A leading space eltakarítására én inkább ezt találtam ki:

PKGS="$PKGS$PKG\n"

Így ugyan trailing space lesz, na de az meg kit zavar, cserébe mínusz egy elágazás, egyszerűbb a kód.

Jogos, viszont úgy tűnik, hogy pacman -Fsq visszatérési értéke mindig 0, függetlenül attól, hogy a fájlt megtalálta-e vagy sem.

Esetleg így lehetne megoldani Arch Linux esetében:


PKG=`pacman -Fsq "$file"`

if [ -z "$PKG" ]; then
    (>&2 echo "$file: No match.")
else
    PKG=`echo "$PKG" | head -1`
fi

vagy [ "$PKG" == "" ], nekem mindegy. :D

sub
### ()__))____________)~~~ ########################
# "Do what you want, but do it right" # X220/Arch