Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

2017-05-20

udev

來源 :
1. udev-強大的device node管理系統
2. Howto--udev rules

一、devfs

linux下有專門的檔系統用來對設備進行管理,devfs和sysfs就是其中兩種。

在2.6內核以前一直使用的是devfs,devfs掛載於/dev目錄下,提供了一種類似於檔案的方法來管理位於/dev目錄下的所有設備,我們知道/dev目錄下的每一個檔案都對應的是一個設備,至於當前該設備存在與否先且不論,而且這些特殊檔是位於根檔系統上的,在製作檔案系統的時候我們就已經建立了這些設備檔,因此通過操作這些特殊檔,可以實現與內核進行交互。但是devfs檔案系統有一些缺點,例如:不確定的設備映射,有時一個設備映射的設備檔可能不同,例如我的U盤可能對應sda有可能對應sdb;沒有足夠的主/輔設備號,當設備過多的時候,顯然這會成為一個問題;/dev目錄下檔太多而且不能表示當前系統上的實際設備;命名不夠靈活,不能任意指定等等。

udev的出現, 解決了在devfs上碰到的3個問題
1.udev能夠根據規則建立device node(這可以解決probing時,device node可能會依probing的順序不同而改變)
2.udev動態建立device node,不會像以前在/dev資料夾下擺一堆多而無用的device node
3.提供user更方便的API存取目前device的資訊,在kernel 2.6以上已提供sysfs這個device管理機制

二、sysfs

正因為上述這些問題的存在,在linux2.6內核以後,引入了一個新的檔案系統sysfs,它掛載於/sys目錄下,跟devfs一樣它也是一個虛擬檔案系統,也是用來對系統的設備進行管理的,它把實際連接到系統上的設備和匯流排組織成一個分階層的檔案目錄,用戶空間的程式同樣可以利用這些資訊以實現和內核的交互,該檔案系統是當前系統上實際設備樹的一個直觀反應,它是通過kobject子系統來建立這個資訊的,當一個kobject被創建的時候,對應的檔案和目錄也就被創建了,位於/sys下的相關目錄下,既然每個設備在sysfs中都有唯一對應的目錄,那麼也就可以被用戶空間讀寫了。用戶空間的工具udev就是利用了sysfs提供的資訊來實現所有devfs的功能的,但不同的是,udev運行在用戶空間中,而devfs卻運行在內核空間,而且udev不存在devfs那些先天的缺陷。很顯然,sysfs將是未來發展的方向。

The top level sysfs directory looks like:
block/
bus/
class/
devices/
firmware/
net/
fs/

devices/ contains a filesystem representation of the device tree. It maps directly to the internal kernel device tree, which is a hierarchy of struct device.

bus/ contains flat directory layout of the various bus types in the kernel. Each bus's directory contains two subdirectories:
       devices/
       drivers/
devices/ contains symlinks for each device discovered in the system that point to the device's  directory under root/.

drivers/ contains a directory for each device driver that is loaded for devices on that particular bus (this assumes that drivers do not span multiple bus types).

fs/ contains a directory for some filesystems. Currently each filesystem wanting to export attributes must create its own hierarchy below fs/ (see ./fuse.txt for an example).

三、udev

udev是一種工具,它能夠根據系統中的硬體設備的狀況動態更新設備檔,包括設備檔的創建,刪除等。設備檔通常放在/dev目錄下,使用udev後,在/dev下面只包含系統中真實存在的設備。它於硬體平臺無關的,位於用戶空間,需要內核sysfs和tmpfs的支援,sysfs為udev提供設備入口和uevent通道,tmpfs為udev設備檔提供存放空間。

udev運作的原理很簡單,它透過netlink得知目前kernel有那些module新增了,在收到kernel module新增的netlink訊息之後,它會先掃描user是否有指派device node rule,如果沒有,會自動根據module的major和minor number建立device node.有一點比較特殊的地方是,udev用inotify監聽rule變化的event,所以可以即時改變device node的狀態,udev的架構圖可參考如下




如前述,udev的功能是動態的對/dev/下的device node做增減的動作。動態增減是為了解決以往/dev下有太多沒用到的device node,而devfs又有一些"先天的缺陷":

1. 屬於kernel space
2. 存在一些可解和解不了的bug
3. 作者消失,維護者也不見了
4....

在種種原因下,udev取代了devfs。當然 devfs也不是沒有優點,如比較小,比較快(速度),比較省(memory),但anyway,過去就讓它過去了。


來吧
基本上,rule是用來在某些條件成立後,執行指令,包括增減device node,並執行外部程式等。比如說,在插入usb disk時,建立/dev/sdb,並mount起來,然後彈出檔案總管。大致條列如下:
1. 將kernel預設的device node改個名字,如把/dev/sdb改成 /dev/apacer-8G (by NAME, no longer works after udev became a part of systemd ??? )
2. 為預設device node建立symbolic link (by SYMLINK)
3. 更彈性的用法,用外部程式來替device node命名 (by PROGRAM)
4. 改變device node的permission和ownership (by GROUP and MODE)
5. device node增減時,執行shell script (by RUN)

時機
通常改變rule是為了改變系統預設的行為,因此,會希望在預設動作前,先完成自己想要做的事。而udev是根據字母排序來parse rule。在rule裡,#開頭的是註解,且每條rule都要在同一行,每條非空行都被視為一條rule。同一個device可以match多條rule,udev會apply每條match的rule。

Syntax
每條rule是由一串(key, value)組成,由comma(“,”)區隔。兩種key:
1. match key(==): 用來識別device,並決定是否要執行該條rule
2. assignment key(=): 當所有的match key都成立,則執行assignment key指定的指令。
每條rule至少要有一個match key和assignment key。
比如說:
        KERNEL==”sdb”, NAME=”usb_disk”
意思是如果kernel report sdb這個device,則建立usb_disk這個device node (就不會有sdb這個node了)。不過這是比較沒鑑別的rule,因為sdb會隨著插入的順序而assign給不同的usb disk,因此最好是使用可uniquely identified的match key,見下述。
常用的match key如下:
KERNEL: kernel所給的預設名字 (如,sda, lp等)
SUBSYSTEM: device所屬的subsystem,如net, block, usb (可由sysfs得知)
DRIVER: 該device所使用的driver
常用的assignment key如下:
NAME: 該device node的名字
SYMLINK: device node的另一個名字,用symbolic link。這個link可以有很多個,所以可以用+=來做assignmet。
PROGRAM: 指定所需執行的外部程式,其stdout可用來指定device node的名字,用%c表示。若不止一個output,也可用%c{1},%c{2}或%c{2+}等表示式。
RUN: 在某些rule成立時,再多執行另一個外部程式。這和PROGRAM有點像,只是PROGRAM是用來產生device node的名字。

正規表示法
match key也有類似正規表示法的東西:
*:match任一個字母,0個或多個
?:match一個字母
[]: match 括號內任一個字母,可以是某個range,如[a-p],[0-9],或是[!1-3]
例如:
KERNEL=”sd*| hd[a-e]”, NAEM=”block/%k”

字串代換
類似printf的表示法:
%k: kernel給的預設名字,如sdb1
%n:kernel給的device number,若%k是sdb1,則%n是1
%c:外部程式的stdout
特殊字元%與$若要拿來當match key,需寫為:%%和$$

Sysfs登場
以上都是解釋,接下來就是真正的應用了。每個device插入系統時,會export一大堆訊息給sysfs,因此在sysfs裡有許多可用的訊息,而且是可以在rule裡直接剪下貼上的,因此udev和sysfs的關係是相當的密切。先從sysfs裡看看有什麼可以挖的吧!
使用udevinfo來query sysfs:
先插入一個usb disk,看看kernel給了什麼預設的名字:
user@user-ubuntu:/etc/udev/rules.d$ cat /proc/partitions
major minor #blocks name
8 0 244198584 sda
8 1 78180291 sda1
8 2 1 sda2
8 5 158200056 sda5
8 6 7815591 sda6
7 0 10240000 loop0
8 16 7823360 sdb
8 17 7819328 sdb1
這樣可知道,是在sdb,而真正要mount的是sdb1,來查一下:
udevadm info -a -p /sys/block/sdb/sdb1 會看到如下的output (只挑其中兩段做例子):
looking at device '/devices/pci0000:00/0000:00:1d.7/usb4/4-3/4-3:1.0/….':
KERNEL=="sdb1"
SUBSYSTEM=="block"
DRIVER==""
ATTR{start}=="8064"
ATTR{size}=="15638656"
ATTR{stat}==" 78 2219 2765 164 4 ……."

looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb4/4-3/4-3:1.0/…':
KERNELS=="52:0:0:0"
SUBSYSTEMS=="scsi"
DRIVERS=="sd"
ATTRS{device_blocked}=="0"
ATTRS{type}=="0"
ATTRS{scsi_level}=="0"
ATTRS{vendor}==" "
ATTRS{model}=="USB FLASH DRIVE "
ATTRS{rev}=="PMAP"
ATTRS{state}=="running"
ATTRS{timeout}=="30"
ATTRS{iocounterbits}=="32"
ATTRS{iorequest_cnt}=="0xe3"
ATTRS{iodone_cnt}=="0xe3"

其實這些資訊都是透過driver export給sysfs,而udevinfo只是透過sysfs裡所記錄的內容,整理過後程現出來有關這個device的屬性。而這些屬性都是可以用來做match key。還有一個原則是每段的屬性是不能交互寫在同一個rule。比如說:
KERNEL==”sdb1”, ATTR{size}=="15638656", NAME=”apacer-disk”
SUBSYSTEMS=="scsi", ATTRS{model}=="USB FLASH DRIVE ", NAME=”apacer-disk”
這兩條rule都是對的,但不能這樣用:
KERNEL==”sdb1”, ATTR{size}=="15638656", ATTRS{model}=="USB FLASH DRIVE ", NAME=”apacer-disk”

Permission and ownership
這個比較直覺,就是設定而已
KERNEL==”sdb1”, ATTR{size}=="15638656", NAME=”apacer-disk”, GROUP=”user”, MODE=”0755”
結果如下:
brwxr-xr-x 1 root user 8, 33 2009-07-03 21:52 apacer-8g

Naming by External Program
比較複雜的情況下,可以存在一支命名程式,使用其stdout來當作device node的名字。在rule中,甚至可以傳參數給這支外部程式。其stdout用%c來表;
示,若有多組output,可用%c{1},%c{2}或%c{2+}這樣的表示方式。舉例如下

SUBSYSTEM=="block", ATTR{size}=="15638656", PROGRAM=”/usr/bin/usb-naming %k”, NAME=”%c”
%k是kernel預設的名字,usb-naming接收此名字後,output結果至stdout。

Run external program upon events
當收到某個udev event後,可再執行某個外部指令。這個跟PROGRAM類似,但不是做naming。比如說,在mount完usb後,做個記錄,可以這麼寫:
SUBSYSTEM=="block", ATTR{size}=="15638656", NAME=”apacer-8g”, RUN+=”/usr/bin/mount-log %k”。

特殊選項
all_partition: 意思大概是為block device建立所有可能的partition,而不是只建一開始偵測到的,不知道這個有什麼應用。
ignore_device:忽略這個event。這個還蠻好用。有些usb有不止一個partition,比如說一個是開機,一個是data。如果每次udev都把這兩個 partition mount起來,但是開機 那個永遠用不到,那就很煩。可用這個選項來忽略開機partition的event。比如:
SUBSYSTEM=="block", ATTR{size}=="1440", OPTIONS+=”ignore_device”
last_rule:對該device不再match之後的rule

2016-12-16

How do I run update-grub2 from a LiveCD?

Boot with your Live CD (ex. partedmagic...).
Once it boots, open a terminal and mount your Debian partition on /mnt. I'm assuming the Debian partition is /dev/sda5, but you should determine this yourself (fdisk -l). Let me know if you need help to do this:
sudo mount /dev/sda5 /mnt
Then mount a few more directories that are needed:
sudo mount --bind /dev /mnt/dev
sudo mount --bind /sys /mnt/sys
sudo mount --bind /proc /mnt/proc
Also, if you have a separate Debian boot partition (pretty uncommon these days, but it may be the case):
sudo mount /dev/sdaX /mnt/boot
How can you tell if you have a boot partition?
Once you have your Debian partition mounted, open /mnt/etc/fstab. If you see an entry for /boot, note which device it is pointing to (/dev/sda4 maybe?). This is the one you have to mount.
Once these are mounted, do chroot to start using the mounted directory as the root partition:
sudo chroot /mnt
You'll get a #/ prompt. First thing to do is confirm that you're using the correct /boot directory. Go to /boot/grub and look at the files there. There should be a bunch of .mod files and a grub.cfg file. If the directory is empty, don't continue, because it means this is NOT your actual boot directory. Look above to see how to determine if you need to mount an additional boot directory.
Once you've confirmed that /boot/ contains the correct files, meaning that it is the correct location, type:
sudo update-grub2
This should rebuild your /boot/grub/grub.cfg file with the menu entries.
Then exit the chroot:
exit
At this point you may want to check that things were correctly updated. For this, cd /mnt/boot/grub and check that grub's files are there, there should be a bunch of .mod files and grub.cfg, the latter should have entries for your Debian kernels. If you only see grub.cfg and no .mod files, it means that this is NOT the correct boot directory, look above for how to mount a separate boot partition.
Unmount the filesystems:
sudo umount /mnt/dev
sudo umount /mnt/sys
sudo umount /mnt/proc
sudo umount /mnt/boot #Only if you mounted it earlier
sudo umount /mnt/
And then reboot, hopefully your Grub menu will be restored.

讀不到GRUB

開機時,BIOS 有偵測到硬碟,但是 GRUB 無法執行,所以判定是 GRUB 有問題。

解決方法

  • 用 Live usb 開機
  • Clonezilla UEFI 開機

用 Live Debian 開機,修改GRUB

做好 Live Debian USB 後,先在 BIOS 設定 UEFI 開機,再插入 USB。
進入到 Debian後,開啟 terminal, 查看硬碟的內容,將 /dev/sda2(根目錄分割區) 掛載到 /mnt, 再將 /dev/sda1(EFI 分割區) 掛載到 /mnt/boot/efi。

# fdisk -l   // 看分割區內容
# mount /dev/sda2 /mnt
# for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i /mnt$i; done
# mount /dev/sda1 /mnt/boot/efi
# chroot /mnt
# grub-install /dev/sda

// 如果遇到 efi variable....
// 退出 chroot
# modprobe efivarfs  // 載入 efi 模組
# for i in /dev /dev/pts /proc /sys /run; do sudo mount -B $i /mnt$i; done
# chroot /mnt
# grub-install /dev/sda
//安裝成功後
# update-grub
# reboot

2016-04-15

使用 NetworkManager 設定網路


Reference 1. Ubuntu NetworkManager 使用要項

從 RHEL7/CentOS7 開始, NetworkManager 已經過更好的改良, 使用 NetworkManager 服務可以一次設定好網路組態與DNS, 而不用再一個一個檔案修改.
nmcli 為 NetworkManager 主要的設定指令, 包含豐富的參數選項, 更容易調整網路位置, 以往在同一張網卡綁定多個 IP 時需要設定多個網路卡網態, 現在也需要使用一行指令即可隨意增加或修改.

開始設定
IP 與閘道
NIC Name: eno16780032
Tag Name: eth0
Type: ethernet
1st IPv4 IP: 192.168.1.192/24
2nd IPv4 IP: 192.168.1.25/24
IPv4 Default Getway: 192.168.1.1

root # nmcli connection add ifname eno16780032 con-name eth0 type ethernet ip4 192.168.1.192/24 gw4 192.168.1.1
root # nmcli connection modify eth0 +ipv4.addresses 192.168.1.25/24

ifname:網路卡名稱(Deivce 編號)
con-name:網路卡別名
type:網路型態
ip4:IPv4 位置,需加上網路區段
gw4:IPv4 閘道位置
設定 DNS
DNS1: 192.168.1.191
DNS1: 8.8.8.8

root # nmcli connection modify eth0 ipv4.dns 192.168.1.191
root # nmcli connection modify eth0 +ipv4.dns 8.8.8.8

ipv4.dns:設定第 1 組 DNS 位置
+ipv4.dns:設定第 2 組 DNS 位置(若有多個會累加)
Start eth0

root # nmcli connection up eth0

檢查設定
查看 IP

root # ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eno16780032: mtu 1500 qdisc mq state UP qlen 1000
    link/ether 00:50:56:bc:5f:90 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.192/24 brd 192.168.1.255 scope global eno16780032
       valid_lft forever preferred_lft forever
    inet 192.168.1.25/24 brd 192.168.1.255 scope global secondary eno16780032
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:febc:5f90/64 scope link
       valid_lft forever preferred_lft forever

查看 Routing table

root # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    1024   0        0 eno16780032
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eno16780032

查看 DNS

root # cat /etc/resolv.conf
# Generated by NetworkManager
search intra.twlab.net
nameserver 192.168.1.191
nameserver 8.8.8.8

2016-04-14

What does backport mean in Debian?

<用例子(1)來說明>

起因是安裝了 mepis ( based on Debian ) 之後, inkscape 無法輸入文字; 用 debian 的 backport 保守追新

以小心嚴謹出名的 debian, 它的穩定版 (stable) 所收錄的某些套件有時候太舊。 若非得用到某些套件的新版不可, 又不想整個系統更新至測試版 (testing), 或許可以到 backport 碰碰運氣。

在命令列下啟動 inkscape, 用錯誤訊息搜尋到 解決方案: 把 libgtk2.0-0 升級到 2.18.6-1。 一開始我也沒想到 debian 有 backport 這個東東, 就只是習慣性地隨意亂找 rpm 檔, 想用 alien 把 fedora 或其他版本較新的 libgtk2 的 rpm 轉成 deb 隨便應急一下。 不過連 alien 的版本也太舊, 無法轉較新的 rpm 冏rz。

後來回到 debian 官方的套件庫網站, 把 「發行版」 和 「section」 都設成 "any", 搜尋 libgtk2.0-0, 終於在 lenny-backports 底下看見 2.18.6-1~bpo50+1。 我還真的給他手工下載, 安裝, 發現相依問題, 再搜尋下一個套件, ... 然後系統就變得怪怪的, 冏rz。 (我對 debian 真的不熟)

以上是錯誤示範, 可略過。 其實根本不需要手工下載。 點進搜尋結果頁面上的 [backports] 連結, 終於學會如何使用 backports:

在 /etc/apt/sources.list 裡面加一句:deb http://backports.debian.org/debian-backports lenny-backports main
更新套件庫摘要索引資料: apt-get update
現在可以安裝新版函式庫了: apt-get -t lenny-backports install libgtk2.0-0
為了安全起見, 還要在 /etc/apt/preferences 最後面加上:
Package: *
Pin: release a=lenny-backports
Pin-Priority: 200
然後 inkscape 就又可以輸入中英文了!

<用例子(2)來說明>



LibreOffice Included In The Debian Squeeze Backports


Almost all the major Linux distributions are using LibreOffice instead of OpenOffice. Today, it has been announced that Debian Squeeze too will get LibreOffice in the backports.
LibreOffice has been available in Debian Wheezy and Debian Sid for a while now. But in the stable release, Debian Squeeze, it is not available. As a Debian policy, new packages are never introduced in the core repository of a stable release. So, it is very unlikely that Debian Squeeze will ever get LibreOffice in its main repository.
So, users of Debian Squeeze who wanted LibreOffice will have to install it from either the unstable or testing archive. However, Debian Squeeze users will no longer have to do that as LibreOffice has been made available in the Squeeze Backports.

How to install LibreOffice in Debian Squeeze from backports

Note: Installing LibreOffice will remove OpenOffice.
To install LibreOffice from the Squeeze backports, you need to add the backports first. To do that open the Terminal and execute:
$ sudo vi /etc/apt/sources.list
Now add the line given below and save the file.
# deb http://backports.debian.org/debian-backports squeeze-backports main
Now update the software list.
$ sudo apt-get update
Finally install LibreOffice with the command
$ apt-get -t squeeze-backports install libreoffice

2016-04-12

NetworkManager conflict with rdnssd and resolvconf


There are a few daemons all wanting to control your DNS in Debian and Ubuntu. However, it’s better to resolve the conflict and leave one daemon in charge instead of having them battle it out on their own.
The Debian 8.0 “Jessie” network installer installs some packages that leaves you with broken domain name resolution in some situations. Ubuntu 15.04 “Vivid Vervet” also does some strange things out of the box. Both leaving Network Manager with a hard time controlling the systems’ DNS settings. Let us correct this by putting Network Manager back in control.
Assumption for leaving all of networking in Network Manager’s capable hands: You want your network to always configure itself automatically with minimal hassle at any location/Wi‐Fi network. Read on if this sounds like your use case.
Some symptoms indicating that you may have DNS resolution problems:
  • Frequent unreliable and slow domain name resolution in browsers and other programs that seemingly correct themselves after some seconds
  • It takes a long time for DNS to start working after connecting to a new network
  • Only IPv6 resolution working when IPv4 resolution is not working, and visa‐versa
  • /etc/resolv.conf is rewritten every few seconds
  • /etc/resolv.conf is missing the “# Generated by NetworkManager” header at the top
Check that you’re actually using Network Manager. In most situations on most distributions this will be the case:
  1. Run service NetworkManager status to confirm that Network Manager is running
  2. Run head /etc/resolv.conf and look for:
    # Generated by NetworkManager
If the header is missing, continue with the below instructions. If it’s there then this post does not hold a solution to your network problem answer. Sorry, but you need to do more research elsewhere to identify your problem.
  1. Run service rdnssd status to see if rdnssd is also running
  2. Run service resolvconf status to see if resolvconf is also running
If two or more services are running we may have successfully identified the problem. Network Manager already covers the functionality provided by rdnssd and resolvconf, so you can go ahead and remove rdnssd and resolvconf.
  1. Run apt-get purge rdnssd to remove it from your system
  2. Run apt-get purge resolvconf to remove it from your system
  3. Run service NetworkManager restart to stop and start the Network Manager daemon so it can find the changes
Wait a minute – or disconnect and reconnect your network – and then repeat step 2 to verify that that Network Manager is back in control over your name resolution.
How did this this problem arise in the first place? According to Debian bug #740998, the Debian network installer (for Debian 8.0 “Jessie”) will install the troublesome rdnssd program if the network installer sees an IPv6 environment. The package is not required on systems managed by Network Manager. Debian 9.0 “Sketch” – currently in the testing release channel – have resolved the problem by making the two packages conflict with each other, preventing them from being installed at the same time.
As for resolvconf, it’s a bit harder to track down how that gets installed. I suspect it’s the network installer again but haven’t confirmed it. Although resolvconf alone can almost manage your /etc/resolv.conf file, it will interfere with Network Manager. resolvconf will not setup IPv6 name servers in all situations

Ubuntu extra

Ubuntu always installs resolvconf. If you’re running Network Manager (see step 2), you can remove it. In addition to resolvconf, you also have to deal with dnsmasq in the mix on Ubuntu. dnsmasq is a caching system meant for situations when DNS is broken. As a side effect, it interferes with DNS and gets in the way of IPv6 DNS servers. Assuming you are not on the Moon or the International Space Station, you do not need a separate system‐level DNS caching daemon and can remove it:
  1. Remove (or comment out) the below line from /etc/NetworkManager/NetworkManager.conf:
    dns=dnsmasq
  2. Run service NetworkManager restart
Wait a minute – or disconnect and reconnect your network – and then repeat step 2 to verify that that Network Manager is back in control over your name resolution.

If your DNS still is broken, you can start blaming your router or internet service provider at this point. Check to see if you also have issues on other machines on the same network. Debian and Ubuntu’s conflicting oddities should have been neutralized, at least.

2016-04-09

Debian 重新編譯套件 (Rebuilding Debian packages)

雖然 Debian 有很方便的 APT 套件管理工具,讓我們省去了許多自行下載、編譯(compile)、安裝程式碼的過程,但總難免會遇到需要修改程式碼的問題,這時就得下載套件原始碼(source code),接著再根據套件相依性安裝其他套件,最後修改程式碼後進行編譯、安裝,但是問題往往不會如此順利與單純......。

一般透過 APT 所安裝的套件,大多都有經過 Debian 開發者的維護與修補(patch),多多少少會與原本套件的原始碼不同,所以下載其他來源(如官方網站)的套件原始碼進行編譯時,有可能會遇到一些光怪陸離、不知如何解決的問題,例如你可能會遇到你所下載的套件原始碼並沒有針對 Debian 環境的修補,而導致無法順利安裝。

累了嗎?也許你可以有更好的選擇!

如果你所需要的套件是能夠透過 apt-get 就能夠安裝的話,同樣地,你也能夠透過 apt-get source 取得這些已經經過 Debian 維護與修補的套件原始碼!這樣有甚麽好處呢?
  1. 不用再辛苦的除錯、修補 (可減少重複前人作過的事)
  2. 確保一定能夠在 Debian 上運作
  3. 節省時間、保留精力
接著以重新編譯 vim 為例,學習如何重新編譯套件。
重新編譯套件之前,需要三個基本的套件 build-essential, devscripts, fakeroot ,可使用以下指令進行安裝:
apt-get install build-essential devscripts fakeroot

接著使用 apt-get source (套件名稱) 指令下載 vim 的套件原始碼(建議使用一個新的資料夾存放原始碼):
mkdir myvim
cd myvim
apt-get source vim

下載完之後,一般會有三個檔案(*.debian.tar.gz, *.dsc, *.orig.tar.gz)及一個資料夾出現,以 .orig.tar.gz 結尾的壓縮檔案是未經任何更動的套件原始碼,以 .debian.tar.gz 結尾的壓縮檔案則內含 Debian 的修補檔、編譯指令等等, .dsc 結尾的檔案則是記載要編譯此套件需滿足的相依性,而最後的資料夾則是含有 Debian 修補檔的套件原始碼。以 vim 為例就是以下三個檔案及一個資料夾:
vim-7.3.547  
vim_7.3.547-7.debian.tar.gz  
vim_7.3.547-7.dsc  
vim_7.3.547.orig.tar.gz

接著可以進入含有修補檔的資料夾中一探究竟:
cd vim-7.3.547

這個資料夾中經過 Debian 維護的修補檔,會存放在 debian 資料夾下的 patches 資料夾內 (debian/patches),修補檔進行修補的順序則是依照 debian/patches/series 檔案內的順序,編譯的指令則是放在 debian 資料夾下的 rules 檔案裡,而原始程式碼則另外存放在 src 資料夾中,整體資料夾結構會如下所示:
vim-7.3.547/
             debian/
                   patches/
                   series
                   rules
             src/
如果只是想修改編譯時的參數,只要依照需求修改 debian/rules 即可。
若有更動到 src 資料夾下的檔案就還需使用以下指令提交修補檔(因為這些程式碼都有經過版本控制)!
dpkg-source --commit

提交時,會詢問修補檔要用甚麽檔名,此處可依需求輸入,例如 hellomyvim.patch 。
Enter the desired patch name:     hellomyvim.patch

提交成功後會出現如下的訊息:
dpkg-source: info: local changes have been recorded in a new patch: ...(略)

編譯之前,需先滿足編譯套件時的相依性,可使用 apt-get build-dep (套件名稱),將需要的套件一併安裝起來。
apt-get build-dep vim

再來使用執行以下指令進行編譯即可:
fakeroot debian/rules clean
fakeroot debian/rules binary

若無任何錯誤訊息,編譯之後,在上一層的資料夾中會出現一個 .deb 檔,使用 dpkg -i 進行安裝即可!
cd ..
dpkg -i vim-7.3.547_.deb

參考資料
http://wiki.debian.org/BuildingTutorial

Install Full Kernel Source on Debian

Question: I need to download and install a full kernel source tree to compile a custom kernel for my Debian or Ubuntu system. What is a proper way to download full kernel source on Debian or Ubuntu?
Before installing full kernel source on your Linux system, ask yourself whether you really need the full kernel source. If you are trying to compile a kernel module or a custom driver for your kernel, you do not need the full kernel source. You only need to install matching kernel header files, and that's it.
You need the full kernel source tree only if you want to build a custom kernel after modifying the kernel code in any way and/or tweaking default kernel options.
Here is how to download and install full kernel source tree from Debian or Ubuntu repositories. While you can download the official kernel source code from https://www.kernel.org/pub/linux/kernel/, using distro's repositories allows you to download a kernel source with the maintainer's patches applied to it.

Install Full Kernel Source on Debian

Before downloading kernel source, install dpkg-dev, which contains a suite of development tools needed to build Debian source packages. Among other things, dpkg-dev contains dpgk-source tool which can extract a Debian source package and automatically apply patches.
$ sudo apt-get install dpkg-dev
Next, run the following command to download full kernel source.
$ apt-get source linux-image-$(uname -r)
Along with the full kernel source (linux_X.X.XX.orig.tar.xz), any available kernel patches (linux_X.X.X+XXX.debian.tar.xz) and source control file (linux_XXXX.dsc) will also be downloaded and stored in the current directory. The .dsc file instructs how the patches are applied to the kernel sources.
Upon the completion of download, the above command will automatically invoke dpkg-source tool, which will unpack the downloaded kernel source in the current directory, and apply downloaded patches according to .dsc file.
The final full kernel source tree will be available in the current directory as "linux-X.X.XX".

If "Can't drop privileges for downloading as file ... by user '_apt'. - pkgAcquire::Run (13: 13: Permission denied)." happens, please check owner & group of current directory.



2016-04-05

Disable WLan if Wired/Cable Network is enabled

You can drop this script to /etc/NetworkManager/dispatcher.d/99-wlan:
#!/bin/bash

if [ "$1" = "eth0" ]; then
    case "$2" in
        up)
            nmcli radio wifi off
            ;;
        down)
            nmcli radio wifi on
            ;;
    esac
fi
Don't forget afterwards:
chmod +x /etc/NetworkManager/dispatcher.d/99-wlan

2015-03-07

GNU / Linux 各種壓縮與解壓縮指令

.7z
套件名稱:p7zip-full。
壓縮:$ 7z a FileName.7z FileName
使用密碼 (PASSWORD) 壓縮:$ 7z a FileName.7z FileName -pPASSWORD
解壓縮:$ 7z x FileName.7z

.bz
壓縮:unkown。
解壓縮1:$ bzip2 -d FileName.bz
解壓縮2:$ bunzip2 FileName.bz

.bz2
套件名稱:bzip2。
壓縮:$ bzip2 -z FileName
解壓縮1:$ bzip2 -d FileName.bz2
解壓縮2:$ bunzip2 FileName.bz2

.gz
套件名稱:gzip。
壓縮 : $ gzip FileName
解壓縮1:$ gunzip FileName.gz
解壓縮2:$ gzip -d FileName.gz

.lha
套件名稱:lha。
壓縮:$ lha -a FileName.lha FileName
解壓縮:$ lha -e FileName.lha

.rar
套件名稱:rar, unrar。
壓縮:$ rar a FileName.rar DirName
解壓縮1:$ rar e FileName.rar
解壓縮2:$ unrar e FileName.rar
.tar (僅打包,無壓縮)
套件名稱:tar。
打包:$ tar cvf FileName.tar DirName
解包:$ tar xvf FileName.tar

.tar.bz
壓縮:unkown。
解壓縮:$ tar jxvf FileName.tar.bz

.tar.bz2
套件名稱:bzip2。
壓縮:$ tar jcvf FileName.tar.bz2 DirName
解壓縮:$ tar jxvf FileName.tar.bz2

.tar.gz
套件名稱:gzip。
壓縮:$ tar zcvf FileName.tar.gz DirName
解壓縮:$ tar zxvf FileName.tar.gz

.tar.tgz
套件名稱:gzip。
壓縮:$ tar zcvf FileName.tar.tgz FileName
解壓縮:$ tar zxvf FileName.tar.tgz

.tar.xz
套件名稱:xz-utils。
壓縮:$ tar Jcvf FileName.tar.xz DirName
解壓縮:$ tar Jxvf FileName.tar.xz

.tar.Z
壓縮:$ tar Zcvf FileName.tar.Z DirName
解壓縮:$ tar Zxvf FileName.tar.Z

.tgz
套件名稱:gzip。
壓縮:$ tar zcvf FileName.tgz FileName
解壓縮:$ tar zxvf FileName.tgz

.xz
套件名稱:xz-utils。
壓縮:$ xz -z FileName
解壓縮:$ xz -d FileName.xz

.Z
壓縮:compress FileName
解壓縮:$ uncompress FileName.Z

.zip
套件名稱:zip。
壓縮:$ zip FileName.zip DirName
解壓縮:$ unzip FileName.zip

2014-05-22

How does a kernel mount the root partition?

非常值得參考的一份文件為 Jserv 所寫的深入理解 Linux 2.6 的 initramfs 機制 (上). 以下是對 initrd 與 initramfs 的概念性比較:

  initrd initramfs
Image 壓縮過的檔案系統 (如 ext2 + gzip) 封裝過的檔案 (cpio + gzip)
實做途徑 block device (RAM disk) tmpfs
首先執行的程式 /linuxrc /init

掛載 rootfs 方式

將欲載入的 rootfs 掛載於某個目錄,再 pivot_root 切換 rootfs 使用 switch_root

 

In ancient times, the kernel was hard coded to know the device major/minor number of the root fs and mounted that device after initializing all device drivers, which were built into the kernel. The rdev utility could be used to modify the root device number in the kernel image without having to recompile it.

Eventually boot loaders came along and could pass a command line to the kernel. If the init= argument was passed, that told the kernel where the root fs was instead of the built in value. The drivers needed to access that still had to be built into the kernel. While the argument looks like a normal device node in the /dev directory, there obviously is no /dev directory before the root fs is mounted, so the kernel can not look up a dev node there. Instead, certain well known device names are hard coded into the kernel so the string can be translated to the device number. Because of this, the kernel can recognize things like /dev/sda1, but not more exotic things like /dev/mapper/vg0-root or a volume UUID.

Later, the initrd came into the picture. Along with the kernel, the boot loader would load the initrdimage, which was some kind of compressed filesystem image ( gzipped ext2 image, gzipped romfs image, squashfs finally became dominant ). The kernel would decompress this image into a ramdisk and mount the ramdisk as the root fs. This image contained some additional drivers and boot scripts instead of a real init. These boot scripts performed various tasks to recognize hardware, activate things like raid arrays and LVM, detect UUIDs, and parse the kernel command line to find the real root, which could now be specified by UUID, volume label and other advanced things. It then mounted the real root fs in /initrd, then executed the pivot_root system call to have the kernel swap / and /initrd, then exec /sbin/init on the real root, which would then unmount /initrd and free the ramdisk.

Finally, today we have the initramfs. This is similar to the initrd, but instead of being a compressed filesystem image that is loaded into a ramdisk, it is a compressed cpio archive. A tmpfs is mounted as the root, and the archive is extracted there. Instead of using pivot_root, which was regarded as a dirty hack, the initramfs boot scripts mount the real root in /root, delete all files in the tmpfs root, then chroot into /root, and exec /sbin/init.