Κατανοώντας τις εξαρτήσεις του apt

Όταν εγκαθιστάμε ένα πακέτο, αυτό απαιτεί την εγκατάσταση άλλων πακέτων, που με την σειρά τους απαιτούν την εγκατάσταση άλλων πακέτων. Στην κορυφή αυτής της ιεραρχίας έχουμε πακέτα όπως το mint-meta-cinnamon που η εγκατάσταση τους φέρνει μαζί της τα πακέτα μιας ολόκληρης διανομής. Αλλά αυτό είναι η μισή ιστορία μιας και οι εξαρτήσεις των πακέτων βάζουν και περιορισμούς στις εκδόσεις των πακέτων που απαιτούν. Η εγκατάσταση κάποιου πακέτου θα συμπαρασύρει προς τα πάνω (ποτέ προς τα κάτω) πολλά άλλα πακέτα. Αν έχουμε πειράξει το σύστημα με πολλά PPA αυτό μπορεί να μην είναι πάντα δυνατό.

Σε αυτόν το σύντομο οδηγό θα δούμε πως μπορούμε να δούμε και να αναλύσουμε τις εξαρτήσεις αυτές. Γιατί να το κάνουμε αυτό; Ας πούμε πως απλά επειδή μπορούμε :smile:

Τα είδη των εξαρτήσεων

Αλλά πριν ας δούμε τα είδη των εξαρτήσεων που μπορεί να έχει ένα πακέτο. Οι κυριότερες από αυτές είναι

  • Depends μια αυστηρή εξάρτηση. Το πρόγραμμα για να τρέξει απαιτεί να υπάρχει το συγκεκριμένο πακέτο. Μια ποιο αυστηρή μορφή είναι το Pre-Depends που απαιτεί να έχει ολοκληρωθεί η εγκατάσταση αυτού του πακέτου πριν γίνει οτιδήποτε άλλο.

  • Recommends μια εξάρτηση που είναι συνιστώμενη και παρέχει επιπλέον λειτουργίες αλλά δεν είναι απαραίτητη. Καλό είναι να την εγκαταστήσουμε.

  • Suggests Μια εξάρτηση που θα παρέχει κάποιες επιπλέον δυνατότητες, αλλά δεν είναι τόσο χρήσιμες. Την εγκαθιστούμε μόνο όταν πραγματικά την θέλουμε. Μια ανάστροφη εξάρτηση είναι η Enhances που αντιστρέφει την σχέση.

Άλλες μορφές εξαρτήσεων είναι η Conflicts και η Breaks που δηλώνουν ασυμβατότητες, καθώς και διάφορες Build-** εξαρτήσεις χρήσιμες για να χτίσεις ένα πακέτο από τον πηγαίο κώδικα. Μια λίστα των εξαρτήσεων υπάρχει εδώ: 7. Declaring relationships between packages — Debian Policy Manual v4.7.4.1.

Εξερευνώντας τις εξαρτήσεις

Το synaptic είναι ένα εργαλείο που μπορούμε να δούμε τις εξαρτήσεις με γραφικό τρόπο

[center]

[/center]

αλλά εδώ θα ασχοληθούμε, με τι άλλο; με το τερματικό. Ας δούμε τις εξαρτήσεις του bash σε βάθος αυτή την φορά. Θα χρησιμοποιήσουμε την εντολή apt-rdepends, που πιθανά να πρέπει να την εγκαταστήσουμε πρώτα

[cmdline] apt-rdepends bash [/cmdline]

[output]
bash
Depends: base-files (>= 2.1.12)
Depends: debianutils (>= 2.15)
PreDepends: libc6 (>= 2.15)
PreDepends: libtinfo6 (>= 6)
base-files
Depends: libc6 (>= 2.3.4)
Depends: libcrypt1 (>= 1:4.4.10-10ubuntu3)
PreDepends: awk
libc6
Depends: libcrypt1 (>= 1:4.4.10-10ubuntu4)
Depends: libgcc-s1
libcrypt1
Depends: libc6 (>= 2.25)
libgcc-s1
Depends: gcc-10-base (= 10.2.0-5ubuntu1~20.04)
Depends: libc6 (>= 2.14)
gcc-10-base
awk
debianutils
PreDepends: libc6 (>= 2.15)
libtinfo6
Depends: libc6 (>= 2.16)
[/output]

Το bash θέλει την base-files (>= 2.1.12) που θέλει το libcrypt1 (>= 1:4.4.10-10ubuntu3) κλπ και τελικά όλα θέλουν κάποια έκδοση της libc6. Το apt θα πρέπει να βρει ποια θα πρέπει να είναι αυτή, μια όχι και τόσο εύκολη δουλεία.

Ένα άλλο ενδιαφέρον ερώτημα είναι το αντίστροφο. Ποια πακέτα απαιτούν το bash για να τρέξουν. Εδώ η λίστα θα είναι πολύ μεγαλύτερη

[cmdline] apt-rdepends -r bash [/cmdline]

[output]
bash
Reverse Depends: backupninja (>= 1.1.0-2.1)
Reverse Depends: bash-builtins (= 5.0-6ubuntu1)
Reverse Depends: bd (>= 1.02-5)
Reverse Depends: biabam (>= 0.9.7-7.2)
Reverse Depends: colortest (>= 20110624-7)
Reverse Depends: cronic (>= 3-2)
Reverse Depends: daps (>= 3.0.0-4)
Reverse Depends: diffmon (>= 20020222-2.6)
Reverse Depends: dpatch (>= 2.0.39)
Reverse Depends: drbl (2.30.5-1)
Reverse Depends: gdm3 (>= 3.34.1-1ubuntu1)
Reverse Depends: git-ftp (>= 1.6.0+dfsg-1)
Reverse Depends: gt5 (>= 1.5.0~20111220+bzr29-3)
Reverse Depends: herisvm (0.8.2-1)
Reverse Depends: imx-code-signing-tool (3.3.0+dfsg-2)
Reverse Depends: libbash (>= 0.9.11-2)


[/output]

Κατασκευή διαγραμμάτων με εξαρτήσεις

Το πρόγραμμα debtree μαζί με το graphviz μας επιτρέπει να δούμε αυτή την πληροφορία με γραφικό τρόπο. Τα διαγράμματα είναι πολύπλοκα και σε ζαλίζουν στην πλήρη μορφή τους, αλλά έφτιαξα ένα μικρό προγραμματάκι για να τα φτιάξω με μια καθαρή μορφή. Ο κώδικάς είναι παρακάτω, αλλά τροποποιήστε τον για να τις δείτε σε πλήρη εικόνα

#!/bin/bash
debtree  --no-recommends --show-installed --rotate --condense --no-conflicts --no-versions $1 > "${1}.dot"
dot -Tpng -o "$1.png" "${1}.dot"

debtree  --show-rdeps --no-recommends --rotate --condense --no-conflicts --no-versions --max-depth=0 $1 > "${1}_r.dot"
dot -Tpng -o "$1_r.png" "${1}_r.dot"

Ας δούμε τι δίνει για το bash
[center]

[/center]

και οι ανάποδες εξαρτήσεις (απόσπασμα).
[center]

[/center]

Εντάξει το bash είναι απλό, αλλά ας δούμε κάτι λίγο ποιο πολύπλοκο. Ας δούμε το systemd.

[center]

[/center]

Λίγο ποιο πολύπλοκο, αλλά όχι κάτι το τραγικό. Κάποιες βασικές βιβλιοθήκες κοντά στον πυρήνα όπως οι libacl και ή libcap2 και κάποια utilities όπως το mount και το login που τραβάνε κάποια άλλα βασικά εργαλεία και βιβλιοθήκες. Οι ανάστροφες εξαρτήσεις είναι κάπως περισσότερες και μοιάζουν με αυτές του bash. Αν τρέξατε το πρόγραμμα θα υπάρχει η εικόνα στον υπολογιστή σας δείτε την.

Ας δούμε κάτι ποιο πολύπλοκο. Την βιβλιοθήκη lcl της Pascal

[center]

[/center]

Εδώ και άν έχουμε εξαρτήσεις! Παρόμοια εικόνα θα δούμε και σε κάποιο άλλο πρόγραμμα όπως το gedit. Δοκιμάστε το. Οι αντίστροφες εξαρτήσεις της lcl δεν έχουν κανένα απολύτως ενδιαφέρον. Κανένα πρόγραμμα στα αποθετήρια του Debian δεν την χρησιμοποιεί.

Ένα κουβάρι απο εξαρτήσεις

Αν το apt είναι να διαχειριστεί μόνο αυτά που βλέπουμε στις εικόνες η δουλεία του θα ήταν απλή. Κάθε προγραμματιστής που έχει κάνει αλγόριθμους σε δέντρα και γράφους μπορεί να το φτιάξει σε λίγες μέρες. Αλλά η διαχείριση των εκδόσεων και τα διαφορετικά είδη των εξαρτήσεων θα του δυσκολέψουν κατα πολύ το έργο.

Εμάς ευτυχώς δεν μας ενδιαφέρουν αυτά. Η χρήση του apt είναι εύκολη ειδικά αν δεν το χρησιμοποιούμε άμεσα.Κάθε διανομή που σέβεται τον εαυτό της διαθέτει σήμερα εξαιρετικά εργαλεία για την εγκατάσταση και απεγκατάσταση προγραμμάτων με γραφικό τρόπο. Αλλά δεν βλάπτει να γνωρίζουμε τι περίπου υπάρχει κάτω από το καπάκι. Και που ξέρεις μπορεί αυτό το μικρό αρθράκι να βοηθήσει κάποια στιγμή που θα έχεις συγκρούσεις στα πακέτα, γιατί το παράκανες με τα ppa, και να σε βοηθήσει να επαναφέρεις το σύστημα.

13 «Μου αρέσει»

Εξαιρετικό κείμενο…

2 «Μου αρέσει»

Αν κάνεις την ίδια διαδικασία στην τελευταία έκδοση του systemd θα δεις πως ο αριθμός των εξαρτήσεων ίσως έχει μειωθεί. Μιας και η καινούργια έκδοση βγήκε πρόσφατα δεν μπορώ να το επιβεβαιώσω, αλλά προς συμπλήρωση του άρθρου, ας πούμε μερικά πράγματα επιπλέον για τις εξαρτήσεις.

Αν ένα πρόγραμμα χρησιμοποιεί μια βιβλιοθήκη μπορεί να το κάνει με δυο τρόπους

  1. 'Έμμεσα με τη χρήση του linker. Μπορείς να βρεις τις βιβλιοθήκες που χρησιμοποιεί κάποιο πρόγραμμα με την εντολή ldd. Παράδειγμα
ldd /usr/lib/systemd/systemd

Για το τι θα δεις κοίταξε εδώ: Lennart Poettering: "2️⃣ Here's the 2nd post highlighting key new feat…" - Mastodon

  1. Με τη χρήση της dlopen() που συνήθως χρησιμοποιείται για plugins. Στην περίπτωση αυτή οι εξαρτήσεις είναι κρυφές.

Το systemd έχει αρχίσει εδώ και κάμποσο καιρό να χρησιμοποιεί τη δεύτερη μέθοδο. Κάτι που κάνει δύσκολο τον αυτόματο υπολογισμό των εξαρτήσεων [1]. Γιατί αυτό; Γιατί παρεκκλίνει της ορθοδοξίας και χιλιόχρονης πρακτικής;

Ίσως να θυμάστε το πρόβλημα που είχε προκύψει με το XZ backdoor. Μεθοδικά και για χρόνια κάποιος ακόμα άγνωστος κυβερνητικός οργανισμός πήρε τον έλεγχο μιας βιβλιοθήκης και πρόσθεσε ένα backdoor. Ευτυχώς, βιάστηκαν να το χρησιμοποιήσουν, έγινε αμέσως αντιληπτό και ελάχιστοι επηρεάστηκαν, μόνον αυτοί που χρησιμοποιούσαν διανομές που χρησιμοποιούν τις τελευταίες εκδόσεις αμέσως μόλις βγουν, αρά σε κανένα σέρβερ που ήταν ο στόχος και δεν αναφέρθηκε καμία ζημία. Ο λόγος της βιασύνης ήταν ακριβώς γιατί άρχισε να υλοποιείται αυτή η μετάβαση.

With v259 we converted almost all our runtime dependencies to use dlopen() instead of explicit shared library linking. We started this process back in v247 with some “leaf” libraries, but with v259 we moved 7 more libraries over, so that in effect only two non-libc libraries remain that we link regularly to: libcrypt (aka the crypt() password hashing API) and libcrypto (aka OpenSSL, and the latter pulls in libz).

Oι εξαρτήσεις που έμειναν (πλην προφανώς της libc) θα αφαιρεθούν στην επόμενη έκδοση. Κάτι που θα το κάνει να έχει λιγότερες εξαρτήσεις σαν init από τα άλλα εναλλακτικά init όπως πχ το s6.

Σαν μια παρενέργεια των παραπάνω η χρήση μνήμης σε ένα ελάχιστο σύστημα ή σε κάποιο container, έχει μειωθεί σημαντικά, αν και εμείς δε θα δούμε κάτι τέτοιο μιας και αυτές τις βιβλιοθήκες τις χρησιμοποιών δεκάδες άλλα βασικά προγράμματα.

To αν θα το δούμε αυτό στις εξαρτήσεις εξαρτάται από το πακετάρισμα προφανώς. Στο debian το systemd έρχεται σαν ένα μεγάλο πακέτο, κάτι που ενισχύει την ψευδαίσθηση περί μονολιθικότητας, αν και σιγά σιγά αυτό αλλάζει πχ το systemd-timesyncd, το systemd-boot και το systemd-resolved είναι πλέον σαν χωριστά πακέτα.

[1] To οποίο στην πράξη δεν είναι κανένα απολύτως πρόβλημα, μιας και υπάρχουν πλέον οι weak dependencies στο ELF. Υποθέτω θα πρέπει να αλλάξει το ldd ή να κάνουμε χρήση του.

readelf -s  | grep WEAK

Επίσης, προστέθηκε το dlopen-metadata στο systemd-analyze.

1 «Μου αρέσει»