Monday, 26 December 2016

[Debian] Khám phá các tiện ích trong package dpkg

Trong package dpkg có gì? 

Bạn hỏi, dpkg trả lời:
$ dpkg -L dpkg | grep bin/
/sbin/start-stop-daemon
/usr/bin/dpkg-split
/usr/bin/dpkg-statoverride
/usr/bin/dpkg
/usr/bin/dpkg-divert
/usr/bin/dpkg-query
/usr/bin/dpkg-maintscript-helper
/usr/bin/dpkg-deb
/usr/bin/update-alternatives
/usr/bin/dpkg-trigger

Các câu lệnh dpkg này làm gì?

Whatis:
$ for binary in $(dpkg -L dpkg | grep bin/); do whatis $(basename $binary); done
start-stop-daemon (8) - start and stop system daemon programs
dpkg-split (1)       - Debian package archive split/join tool
dpkg-statoverride (8) - override ownership and mode of files
dpkg (1)             - package manager for Debian
dpkg-divert (8)      - override a package's version of a file
dpkg-query (1)       - a tool to query the dpkg database
dpkg-maintscript-helper (1) - works around known dpkg limitations in maintainer scripts
dpkg-deb (1)         - Debian package archive (.deb) manipulation tool
update-alternatives (8) - maintain symbolic links determining default commands
dpkg-trigger (1)     - a package trigger utility

dpkg - chương trình quản lý package cho Debian

dpkg có các câu lệnh để :

- cài đặt
- liệt kê
- gỡ bỏ
các package (file .deb) trên hệ thống (Debian, ubuntu ...). Các file .deb bản chất là các file archive (đóng gói) nhiều file khác, bao gồm các file cấu hình, thư viện, file binary để chạy, các script mà dpkg sẽ chạy lúc cài đặt / gỡ bỏ, file thông tin về package ...
Ví dụ sau dùng lệnh "ar" để giải nén file .deb
$ file /var/cache/apt/archives/zip_3.0-8_amd64.deb
/var/cache/apt/archives/zip_3.0-8_amd64.deb: Debian binary package (format 2.0)
$ mkdir /tmp/extracted; cd /tmp/extracted; ar -x /var/cache/apt/archives/zip_3.0-8_amd64.deb
$ ls
control.tar.gz  data.tar.gz  debian-binary
$ whatis ar
ar (1)               - create, modify, and extract from archives
Xem thêm các lệnh dpkg tại đây

Khi chạy với một số option nhất định, dpkg đóng vai trò như 1 front-end, sẽ truyền và gọi các câu lệnh khác (backend) như dpkg-deb và dpkg-query:
       dpkg can also be used as a front-end to dpkg-deb(1) and dpkg-query(1). The list of  sup‐
       ported  actions  can  be  found  later  on in the ACTIONS section. If any such action is
       encountered dpkg just runs dpkg-deb or dpkg-query with the parameters given to  it,  but
       no  specific  options are currently passed to them, to use any such option the back-ends
       need to be called directly.
man 1 dpkg

dpkg-divert (8)  - override a package's version of a file

divert - lái sang một hướng khác.
"diversions" là một cách để ép ``dpkg`` không cài một file vào vị trí mà nó được chỉ định, thay vào đó dpkg sẽ đưa file tới một vị trí khác. Tác dụng:
- tránh conflict khi 2 file cùng tranh chấp một chỗ.
- ghi đè file config mà package cung cấp.

Lấy danh sách các "diversion":
$ dpkg-divert --list | wc -l
11
Lệnh này thực chất sẽ đọc nội dung file /var/lib/dpkg/diversions và in ra output ở dạng dễ đọc.

Để "divert" một file, chạy lệnh:
# dpkg-divert --local --rename --add /sbin/initctl
Leaving 'local diversion of /sbin/initctl to /sbin/initctl.distrib'
# ls -l /sbin/initctl*
-rwxr-xr-x 1 root root 193512 Apr 11  2014 /sbin/initctl.distrib
root@9e97755ce50e:/# cat /sbin/initctl
root@9e97755ce50e:/# dpkg-divert --list | grep initctl
local diversion of /sbin/initctl to /sbin/initctl.distrib
Để remove một diversion,chạy:
$ dpkg-divert --local --rename --remove /sbin/initctl
Removing 'local diversion of /sbin/initctl to /sbin/initctl.distrib'
root@9e97755ce50e:/# ls -l /sbin/initctl*
-rwxr-xr-x 1 root root 193512 Apr 11  2014 /sbin/initctl

Tổng kết:
Lệnh dpkg-divert thêm/bớt một file vào danh sách diversions, có thể move file đó nếu --rename được dùng. Lệnh dpkg khi cài các package sẽ tham khảo danh sách diversion để đưa các file vào vị trí mới (diversions) thay vì vị trí nó được chỉ định ban đầu.

--local  chỉ ra đây không là diversion của riêng package nào mà là của tất cả package
Vì thường diversion sẽ cho một package cụ thể:
$ dpkg-divert --list | head -n1
diversion of /usr/share/man/man1/pod2latex.1.gz to /usr/share/man/man1/pod2latex.bundled.1.gz by libpod-latex-perl
Câu lệnh trên cho biết ta có diversion cho package libpod-latex-perl

--add thêm diversion vào database (file /var/lib/dpkg/diversions)
--remove xoá diversion khỏi database
--rename: dịch chuyển file nếu file mới chưa tồn tại.

Việc sử dụng diversion ở các ví dụ trên là giải pháp workaround cho vấn đề không chạy được các lệnh initctl (upstart) trên docker image  lúc cài một package.

Ví dụ cài nginx và đặt file binary vào /tmp/nginx thay vì /usr/sbin/nginx như mặc định trên Ubuntu 14.04:
# dpkg-divert --divert /tmp/nginx --local --add /usr/sbin/nginx
Leaving 'local diversion of /usr/sbin/nginx to /tmp/nginx'
# dpkg-divert --list | grep nginx
local diversion of /usr/sbin/nginx to /tmp/nginx
# apt-get install -y nginx
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  nginx-common nginx-core
Suggested packages:
  fcgiwrap nginx-doc
The following NEW packages will be installed:
  nginx nginx-common nginx-core
...
Setting up nginx (1.4.6-1ubuntu3.7) ...
# dpkg -L nginx-core | grep bin/
/usr/sbin/nginx
# ls -l /usr/sbin/nginx
ls: cannot access /usr/sbin/nginx: No such file or directory
# ls -l /tmp/nginx
-rwxr-xr-x 1 root root 873176 Oct 27 15:35 /tmp/nginx

dpkg-split - cắt nhỏ file deb

Nếu một file deb có kích thước quá lớn so với thiết bị lưu trữ (thời dùng đĩa mềm - floppy disk chẳng hạn 😲), ta cần cắt nó ra, copy sang máy khác, rồi sau đó nối lại. Ví dụ sau đây cắt một file deb rồi lại nối lại các mảnh ghép, kết quả trước và sau khi cắt có mã MD5 trùng nhau - tức là 2 file giống hệt nhau.
$ du -h python2.7-dev_2.7.6-8ubuntu0.3_amd64.deb
264K    python2.7-dev_2.7.6-8ubuntu0.3_amd64.deb
$ dpkg-split --split --partsize 100 python2.7-dev_2.7.6-8ubuntu0.3_amd64.deb
Splitting package python2.7-dev into 3 parts: 1 2 3 done
$ ls -l python2.7-dev_2.7.6-8ubuntu0.3_amd64.*
-rw-r--r-- 1 root root 101596 Dec 26 14:11 python2.7-dev_2.7.6-8ubuntu0.3_amd64.1of3.deb
-rw-r--r-- 1 root root 101596 Dec 26 14:11 python2.7-dev_2.7.6-8ubuntu0.3_amd64.2of3.deb
-rw-r--r-- 1 root root  66636 Dec 26 14:11 python2.7-dev_2.7.6-8ubuntu0.3_amd64.3of3.deb
-rw-r--r-- 1 root root 269168 Dec 26 14:10 python2.7-dev_2.7.6-8ubuntu0.3_amd64.deb
$ dpkg-split --output py27joined.deb --join python2.7-dev_2.7.6-8ubuntu0.3_amd64.*of*
Putting package python2.7-dev together from 3 parts: 1 2 3 done
$ md5sum py27joined.deb
15530c3ad41beed2353dc8c309410f4e  py27joined.deb
$ md5sum python2.7-dev_2.7.6-8ubuntu0.3_amd64.deb
15530c3ad41beed2353dc8c309410f4e  python2.7-dev_2.7.6-8ubuntu0.3_amd64.deb

update-alternatives

update-alternatives là công cụ giúp quản lý các symlink để quyết định câu lệnh nào là default (mặc định). Xem bài viết chi tiết ở đây

dpkg-statoverride

Câu lệnh để quy định mode/owner của một file cụ thể, sẽ được set sau khi cài package xong.
In ra danh sách các file được override owner/mode so với file package cung cấp:

$ dpkg-statoverride --list
root mlocate 2755 /usr/bin/mlocate
root landscape 4754 /usr/lib/landscape/apt-update
root ssl-cert 710 /etc/ssl/private
root crontab 2755 /usr/bin/crontab
Thực chất là in ra nội dung file /var/lib/dpkg/statoverride

Mode ở đây là các số ở hệ octal (bát phân).
Thêm một file vào danh sách override:
# dpkg-statoverride --add root root 2755 /tmp/familug
# dpkg-statoverride --list | grep familug
root root 2755 /tmp/familug
Để xoá đi, dùng --remove PATH_FILE

start-stop-daemon - khởi động / dừng một system-process

Thử start và stop (gửi SIGTERM) rsyslog - sử dụng đường dẫn đến binary để tìm đến process đang chạy thay vì chỉ định PID (giống lệnh killall):
# ps xau | grep rsyslo[g]
syslog   19783  0.0  0.3 348420  3452 ?        Ssl  14:31   0:00 rsyslogd
# start-stop-daemon --start --exec /usr/sbin/rsyslogd -v
/usr/sbin/rsyslogd already running. # đang chạy - không làm gì thêm
# start-stop-daemon --stop --exec /usr/sbin/rsyslogd -v
Stopped /usr/sbin/rsyslogd (pid 19783). # tắt process 

Câu lệnh này được sử dụng rất nhiều trong các SysV script để quản lý các service:
$ grep -Rin start-stop-daemon /etc/init.d/ | wc -l
44
Hết.
HVN at http://www.familug.org/ and http://pymi.vn