Product SiteDocumentation Site

5.2. Package Meta-Information

Gói Debian không chỉ là một lưu trữ của các tệp tin dành cho cài đặt. Nó là một phần tổng thể lớn hơn, và nó mô tả mối quan hệ với các gói Debian khác (phụ thuộc, xung đột hay gợi ý). Nó còn cung cấp các kịch bản cho phép thực hiện các câu lệnh ở các giai đoạn khác nhau trong vòng đời của gói (cài đặt, gỡ bỏ và nâng cấp). Các dữ liệu này được sử dụng bởi trình quản lý gói nhưng không phải là một phần của phần mềm đóng gói; những dữ liệu trong gói, được gọi với tên là “meta-information” (thông tin về các thông tin khác).

5.2.1. Mô tả: tệp tin control

Tệp này sử dụng một cấu trúc giống như headers của email (định nghĩa ở RFC 2822). Ví dụ, cho gói apt, tệp tin control trông giống như sau:
$ apt-cache show apt
Package: apt
Version: 1.0.9.6
Installed-Size: 3788
Maintainer: APT Development Team <deity@lists.debian.org>
Architecture: amd64
Replaces: manpages-it (<< 2.80-4~), manpages-pl (<< 20060617-3~), openjdk-6-jdk (<< 6b24-1.11-0ubuntu1~), sun-java5-jdk (>> 0), sun-java6-jdk (>> 0)
Depends: libapt-pkg4.12 (>= 1.0.9.6), libc6 (>= 2.15), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 4.9), debian-archive-keyring, gnupg
Suggests: aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), apt-doc, python-apt
Conflicts: python-apt (<< 0.7.93.2~)
Breaks: manpages-it (<< 2.80-4~), manpages-pl (<< 20060617-3~), openjdk-6-jdk (<< 6b24-1.11-0ubuntu1~), sun-java5-jdk (>> 0), sun-java6-jdk (>> 0)
Description-en: commandline package manager
 This package provides commandline tools for searching and
 managing as well as querying information about packages
 as a low-level access to all features of the libapt-pkg library.
 .
 These include:
  * apt-get for retrieval of packages and information about them
    from authenticated sources and for installation, upgrade and
    removal of packages together with their dependencies
  * apt-cache for querying available information about installed
    as well as installable packages
  * apt-cdrom to use removable media as a source for packages
  * apt-config as an interface to the configuration settings
  * apt-key as an interface to manage authentication keys
Description-md5: 9fb97a88cb7383934ef963352b53b4a7
Tag: admin::package-management, devel::lang:ruby, hardware::storage,
 hardware::storage:cd, implemented-in::c++, implemented-in::perl,
 implemented-in::ruby, interface::commandline, network::client,
 protocol::ftp, protocol::http, protocol::ipv6, role::program,
 role::shared-lib, scope::application, scope::utility, sound::player,
 suite::debian, use::downloading, use::organizing, use::searching,
 works-with::audio, works-with::software:package, works-with::text
Section: admin
Priority: important
Filename: pool/main/a/apt/apt_1.0.9.6_amd64.deb
Size: 1107560
MD5sum: a325ccb14e69fef2c50da54e035a4df4
SHA1: 635d09fcb600ec12810e3136d51e696bcfa636a6
SHA256: 371a559ce741394b59dbc6460470a9399be5245356a9183bbeea0f89ecaabb03

5.2.1.1. Các phụ thuộc: trường Depends

Các phụ thuộc được định nghĩa ở trường Depends trong tiêu đề gói. Đây là danh sách các điều kiện để đáp ứng cho các gói làm việc chính xác - thông tin này được sử dụng bởi các công cụ như apt để cài đặt các thư viện cần thiết, với các phiên bản thích hợp phù hợp với các sự phụ thuộc của gói được cài đặt. Đối với mỗi phụ thuộc, nó có thể hạn chế phạm vi của các phiên bản đáp ứng được điều kiện đó. Nói cách khác, nó có thể để bày tỏ một thực tế rằng chúng ta cần gói libc6 trong một phiên bản tương đương hoặc lớn hơn “2.15” (viết “libc6 (>= 2.15)”). Toán tử so sánh phiên bản như sau:
  • <<: bé hơn;
  • <=: bé hơn hoặc bằng;
  • =: bằng (hãy nhớ “2.6.1” không bằng với “2.6.1-1”);
  • >=: lớn hơn hoặc bằng;
  • >>: lớn hơn.
Trong danh sách các điều kiện cần đáp ứng, các dấu phẩy xem như là một dấu phân cách. Nó phải được hiểu như là toán tử logic “and”. Trong các điều kiện, các thanh dọc (“|”) thể hiện là một toán tử logic “or” (đó là phép hội “or”, không phải là hoặc cái này hoặc cái kia độc quyền “either/or”). Phép “and” được ưu tiên hơn, nó có thể được sử dụng như nhiều lần khi cần thiết. Do đó, sự phụ thuộc “(A or B) and C” được viết A | B, C. Ngược lại, khái niệm “A or (B and C)” nên viết là “(A or B) and (A or C)”, khi trường Depends không có dấu ngoặc mà thay đổi thứ tự ưu tiên giữa các toán tử logic “or” and “and”. Như vậy sẽ được viết thành A | B, A | C.
Hệ thống phụ thuộc là một cơ chế tốt để đảm bảo các hoạt động của một chương trình, nhưng nó còn sử dụng cho “meta-packages”. Đây là gói không chứa nội dung chương trình mà chỉ mô tả phụ thuộc. Nó tạo điều kiện cho quá trình cài đặt của một nhóm các chương trình được phù hợp chọn trước bởi nhà bảo trì meta-package; như vậy, apt install meta-package sẽ tự động cài đặt tất cả các chương trình sử dụng các phụ thuộc của meta-package. Các gói gnome, kde-full and linux-image-amd64 là ví dụ của meta-packages.

5.2.1.2. Xung đột: trường Conflicts

Trường Conflicts chỉ ra rằng khi một gói không thể cài đặt trong trường hơp với gói khác. Phần lớn lý do chung cho vấn đề này là cả hai gói đều bao gốm giống tên nhau, hoặc cung cấp các dịch vụ như nhau ở cùng cổng TCP, hoặc sẽ cản trở hoạt động của gói kia.
dpkg sẽ từ chối cài đặt một gói nếu nó gây xung đột với một trong các gói đã cài đặt, ngoại trừ gói mới đặc biệt nó sẽ “thay thế” gói đã cài đặt, trong trường hợp dpkg sẽ chọn để thay thế gói cũ với gói mới, nó sẽ tự động đề nghị gỡ bỏ gói có vẻ có vấn đề

5.2.1.3. Không tương thích: trường Breaks

Trường Breaks có tác dụng khá giống với trường Conflicts, nhưng với một nghĩa đặc biệt. Nó báo hiệu rằng nếu cài đặt gói này sẽ “làm hỏng” gói khác (hoặc cụ thể là phiên bản của nó). Nói chung, sự không thương thích này giữa hai gói là tạm thời, và trường Breaks quan hệ đặc biệt với các phiên bản không tương thích.
dpkg sẽ từ chối cài đặt một gói nếu nó làm hỏng một gói đã cài đặt, và apt sẽ cố giải quyết vấn đề bằng cách cập nhật gói đó lên phiên bản mới nhất (đây là giả định sẽ sửa được và do vậy lại tương thích)
Tình hình này có thể xảy ra trong trường hợp cập nhật mà không tương thích ngược: Trong trường hợp này nếu phiên bản mới hơn không còn các chức năng như phiên bản cũ, và gây ra một sự cố trong chương trình khác mà không làm gì đặc biệt. Trường Breaks ngăn cản người dùng gặp cả những vấn đề này.

5.2.1.4. Cung cấp Các mục: Trường Provides

Trường này giới thiệu khái niệm rất thú vị của một “gói ảo”. Nó có nhiều vai trò, nhưng hai trong số đó là quan trọng nhất. Vai trò thứ nhất bao gồm trong sử dụng gói để liên kết với một dịch vụ chung với nó (gói “cung cấp” dịch vụ). Vai trò thứ hai chỉ ra rằng một gói hoàn toàn thay thế một gói khác, và do mục đích này mà nó cũng có thể đáp ứng các phụ thuộc mà gói kia đáp ứng. Do đó có khả năng tạo ra một gói thay thế mà không cần sử dụng cùng tên gói.
5.2.1.4.1. Đang cung cấp một “Service”
Chúng ta sẽ thảo luận về trường hợp đầu tiên chi tiết hơn với một ví dụ: tất cả máy chủ mail, ví dụ như postfix hoặc sendmail “cung cấp” gói mail-transport-agent ảo. Thế nên, bất kỳ gói nào cần dịch vụ này để làm tính năng (ví dụ: quản lý mailing list, hay như là smartlist hoặc sympa) đơn giản là chỉ cần chỉ định phụ thuộc của nó yêu cầu một mail-transport-agent thay vi chỉ định một danh sách lớn các giải pháp có thể (ví dụ: postfix | sendmail | exim4 | …). Hơn nữa, không cần thiết phải cài đặt hai máy chủ mail trên cùng một máy, đó là lý do mỗi gói này tuyên bố xung đột với gói ảo mail-transport-agent. Một xung đột giữ gói của chính nó sẽ bị hệ thống bỏ qua nhưng kỹ thuật này sẽ cấm cài đặt hai máy chủ mail song song.
5.2.1.4.2. Khả năng trao đổi với một Gói khác
Trường Provides cũng thú vị khi nội dung của một gói được bao gồm trong một gói lớn hơn. Lấy ví dụ: libdigest-md5-perl Mô đun Perl là một mô đun tùy chọn trong Perl 5.6 và đã được tích hợp theo chuẩn ở Perl 5.8 (và các phiên bản sau này, như 5.20 có trong Jessie). Gói perl kể từ phiên bản 5.8 đã tuyên bố Provides: libdigest-md5-perl để các gói phụ thuộc gói này được đáp ứng nếu người dùng có Perl 5.8 (hoặc mới hơn), gói libdigest-md5-perl cuối cùng đã bị xóa, vì nó không còn có mục đích nào khi các phiên bản Perl cũ bị xóa.
Sử dụng trường Provides để không phá vỡ sự phụ thuộc

Hình 5.1. Sử dụng trường Provides để không phá vỡ sự phụ thuộc

Tính năng này rất hữu ích vì không thể lường trước được sự biến động của sự phát triển và cần phải có khả năng điều chỉnh để đổi tên và thay thế tự động các phần mềm đã lỗi thời.
5.2.1.4.3. Hạn chế trong Quá khứ
Các gói ảo được sử dụng để bị một số hạn chế, đáng kể nhất là không có số phiên bản. Trở lại ví dụ trước, một sự phụ thuộc như Depends: libdigest-md5-perl (>= 1.6), bất chấp sự có mặt của Perl_5.10, sẽ không bao giờ được coi là thỏa mãn bởi hệ thống gói - trong khi trên thực tế nó rất có thể là thỏa mãn. Không biết về điều này, hệ thống gói đã chọn lựa chọn ít rủi ro nhất, giả định rằng các phiên bản không khớp.
Giới hạn này đã được bỏ trong dpkg1.17.11 và không còn liên quan đến Jessie. Gói có thể gán một phiên bản cho gói ảo mà chúng cung cấp với sự phụ thuộc như Provides: libdigest-md5-perl (= 1.8).

5.2.1.5. Thay thế Các tệp: Trường Replaces

Trường Replaces chỉ ra rằng gói chứa các tệp có trong gói khác nhưng gói đó có quyền thay thế chúng một cách hợp pháp. Nếu không sử dụng đặc tả này, dpkg sẽ báo lỗi, nó không thể ghi đè lên các tệp của một gói khác (về mặt kỹ thuật, dĩ nhiên có thể buộc nó làm như vậy với tùy chọn --force-overwrite, nhưng đó không phải là cách hay). Điều này cho phép xác định các vấn đề tiềm ẩn và yêu cầu người bảo trì phải nghiên cứu vấn đề trước khi lựa chọn có nên thêm vào một trường như thế hay không.
Việc sử dụng trường này là hợp lý khi tên gói thay đổi hoặc khi gói được bao gồm trong một gói khác. Điều này cũng xảy ra khi người bảo trì quyết định phân phối các tệp tin khác nhau giữa các gói nhị phân khác nhau được tạo ra từ cùng một gói nguồn: tệp được thay thế không còn thuộc về gói cũ nữa, nhưng chỉ cần tệp thay thế mới.
Nếu tất cả các tệp trong gói được cài đặt đã được thay thế, gói được coi là đã bị xóa. Cuối cùng, trường này cũng khuyến khích dpkg để gỡ bỏ gói thay thế nơi có sự xung đột.

5.2.2. Kịch bản Cấu hình

Ngoài tệp control, tệp nén control.tar.gz của mỗi gói Debian có thể chứa một số kịch bản, được gọi bởi dpkg ở các giai đoạn khác nhau trong việc xử lý gói. Chính sách Debian mô tả có thể có nhiều trường hợp chi tiết, xác định các kịch bản được gọi và các đối số mà chúng nhận được. Các thực hiện kịch bản này có thể phức tạp, vì nếu một trong các kịch bản không thành công, dpkg sẽ cố gắng trở lại trạng thái trước bằng cách hủy bỏ quá trình cài đặt hoặc xóa bỏ tiến trình (trong chừng mực có thể).
Nói chung, kịch bản preinst được thực hiện trước khi cài đặt gói, trong khi kịch bản postinst là sau khi cài đặt. Tương tự, prerm được gọi trước khi loại bỏ một gói và postrm sau khi loại bỏ gói xong. Bản cập nhật của một gói tương đương với việc loại bỏ phiên bản trước đó và cài đặt gói mới. Không thể mô tả chi tiết tất cả các kịch bản có thể ở đây nhưng chúng ta sẽ thảo luận hai vấn đề phổ biến nhất: cài đặt/cập nhật và gỡ bỏ.

5.2.2.1. Cài đặt và Nâng cấp

Dưới đây là những gì xảy ra trong quá trình cài đặt (hoặc cập nhật):
  1. Đối với cập nhật, dpkg gọi old-prerm upgrade new-version.
  2. Vẫn với cập nhật, dpkg sau đó thực hiện new-preinst upgrade old-version; đối với lần cài đặt đầu tiên, nó thực hiện new-preinst install. Có thể thêm phiên bản cũ vào tham số theo sau, nếu gói đã được cài đặt và gỡ bỏ trước (nhưng không bị xóa, các tệp cấu hình đã được giữ lại).
  3. Các tệp gói mới sau đó được giải nén. Nếu một tập tin đã tồn tại, nó được thay thế, nhưng một bản sao lưu tạm thời được thực hiện.
  4. Cho cập nhật, dpkg thực hiện old-postrm upgrade new-version.
  5. dpkg cập nhật tất cả dữ liệu nội bộ (danh sách tệp, tập lệnh cấu hình, v.v.) và loại bỏ các bản sao lưu của các tệp được thay thế. Đây là điểm không trở lại: dpkg không còn truy cập vào tất cả các yếu tố cần thiết để trở về trạng thái trước đó.
  6. dpkg sẽ cập nhật các tệp cấu hình, hỏi người dùng quyết định xem nó có thể tự động quản lý tác vụ này không. Các chi tiết của thủ tục này được thảo luận trong Phần 5.2.3, “Checksums, Danh sách Tệp Cấu hình”.
  7. Cuối cùng, dpkg cấu hình gói bằng cách thực hiện new-postinst configure last-version-configured.

5.2.2.2. Xóa Gói

Dưới đây là những gì xảy ra trong quá trình loại bỏ gói:
  1. dpkg gọi prerm remove.
  2. dpkg loại bỏ tất cả các tệp của gói, trừ các tệp cấu hình và tập lệnh cấu hình.
  3. dpkg thực hiện postrm remove. Tất cả các tập lệnh cấu hình, ngoại trừ postrm, sẽ bị xóa. Nếu người dùng không sử dụng tùy chọn “purge”, quá trình dừng ở đây.
  4. Để xóa toàn bộ gói (lệnh được gọi với dpkg --purge hoặc dpkg -P), các tệp cấu hình cũng sẽ bị xoá. Cũng như là một số lượng nhất định các bản sao (*.dpkg-tmp, *.dpkg-old, *.dpkg-new) và các tập tin tạm; dpkg sau đó thực hiện postrm purge.
Bốn kịch bản được nêu chi tiết ở trên được bổ sung bởi một tập lệnh config, được cung cấp bởi các gói sử dụng debconf để thu thập thông tin từ người dùng để cấu hình. Trong quá trình cài đặt, kịch bản này xác định chi tiết các câu hỏi được yêu cầu bởi debconf. Câu trả lời được ghi lại trong cơ sở dữ liệu debconf để tham khảo trong tương lai. Tập lệnh thường được thực thi bởi apt trước khi cài đặt từng gói một để nhóm tất cả các câu hỏi và yêu cầu tất cả các người dùng vào lúc bắt đầu quá trình. Các tập lệnh trước và sau khi cài đặt có thể sử dụng thông tin này để hoạt động theo ý muốn của người dùng.

5.2.3. Checksums, Danh sách Tệp Cấu hình

Ngoài các kịch bản bảo trì và dữ liệu điều khiển đã được đề cập trong các phần trước, tệp nén control.tar.gz của một gói Debian có thể chứa các tệp tin thú vị khác. Đầu tiên, md5sums, chứa checksums MD5 cho tất cả các tệp của gói. Ưu điểm chính của nó là nó cho phép dpkg --verify (chúng ta sẽ nghiên cứu trong Phần 14.3.3.1, “Auditing Packages with dpkg --verify) để kiểm tra xem các tệp này đã được sửa đổi từ khi cài đặt hay không. Lưu ý rằng khi tệp này không tồn tại, dpkg sẽ tự động tạo ra nó trong thời gian cài đặt (và lưu trữ nó trong cơ sở dữ liệu dpkg giống như các tệp kiểm soát khác).
conffiles liệt kê các tệp tin gói phải được xử lý như tệp cấu hình. Các tệp cấu hình có thể được quản trị viên sửa đổi và dpkg sẽ cố gắng bảo vệ những thay đổi đó trong quá trình cập nhật gói.
Trong trường hợp này, dpkg hoạt động thông minh nhất có thể: nếu tập tin cấu hình tiêu chuẩn không thay đổi giữa hai phiên bản, nó không làm gì cả. Tuy nhiên, nếu tệp đã thay đổi, nó sẽ cố gắng cập nhật tệp này. Có hai trường hợp: quản trị viên không chạm vào tệp cấu hình này, trong trường hợp đó dpkg tự động cài đặt phiên bản mới; Hoặc tập tin đã được sửa đổi, trong trường hợp này dpkg yêu cầu quản trị viên phiên bản nào họ muốn sử dụng (bản cũ có sửa đổi, hoặc phiên bản mới được cung cấp kèm theo gói). Để hỗ trợ đưa ra quyết định này, dpkg cung cấp để hiển thị “diff” cho thấy sự khác biệt giữa hai phiên bản. Nếu người dùng chọn giữ lại phiên bản cũ, tệp mới sẽ được lưu trữ ở cùng vị trí trong một tệp có đuôi .dpkg-dist. Nếu người dùng chọn phiên bản mới, phần cũ sẽ được giữ lại trong một tệp có đuôi .dpkg-old. Một hành động khả dụng khác bao gồm tạm ngưng dpkg để chỉnh sửa tệp và cố gắng cài đặt lại các sửa đổi có liên quan (trước đây được xác định với diff).