在嵌入式Linux中,經常涉及到格式化硬盤,常用的工具就是fdisk,這工具功能強大,busybox裡面也實現了fdisk。當busybox實現的fdisk是簡化版,與原版的GNU的fdisk相差挺大的,主要是缺少一些細節性的功能。
本文主要是說明fdisk寫入MBR的一個磁盤可選id,這個區域可以用來唯一的標記一塊硬盤,總共有4個字節,2的32次方中情況。
以後將會詳細的介紹MBR結構。。
以下是摘自維基百科的一個表格,介紹MBR的結構:
Structure of a master boot record
Address DescriptionSize in bytes
Hex Oct Dec
0000 0000 0 code area 440(max. 446)
01B8 0670 440 disk signature (optional)4 (本文涉及到該區域)
01BC 0674 444 Usually nulls; 0x00002
01BE 0676 446 Table of primary partitions(Four 16-byte entries, IBM partition table scheme)64
01FE 0776 510 55h MBR signature 2
01FF 0777 511 AAh
MBR, total size: 446 + 64 + 2 = 512
如果要修改該區域,需要確保該區域的地址,地址是:440-443;該區域占4個字節,只需要用一個int型變量即可讀取。
源碼如下:
- int main(void)
- {
- int fd;
- unsigned int id;
- fd = open("/dev/sda", O_RDONLY);
- if (fd < 0) {
- perror("open");
- exit(1);
- }
-
- lseek(fd, 440, SEEK_SET);
- if (read(fd, &id, 4) != 4) {
- perror("read");
- close(fd);
- exit(1);
- }
- close(fd);
- return 0;
- }
上面已經說了,busybox可能沒有實現fdisk這個功能,有些時候嵌入式系統需要標志硬盤ID,所以需要隨機產生一個數字來寫入硬盤的MBR的磁盤可選id的區域,這隨便產生一個隨機數就行,可以使用time(NULL)獲取,很簡單。
在GNU的fdisk源碼中,使用以下函數來生成唯一id:
- static unsigned int get_random_id(void) {
- int fd;
- unsigned int v;
- ssize_t rv = -1;
-
- fd = open("/dev/urandom", O_RDONLY);
- if (fd >= 0) {
- rv = read(fd, &v, sizeof v);
- close(fd);
- }
-
- if (rv == sizeof v)
- return v;
-
- /* Fallback: sucks, but better than nothing */
- return (unsigned int)(getpid() + time(NULL));
- }
該函數是去讀取/dev/urandom設備,該設備用於產生一個無符號的隨機數,如果讀取失敗,將會直接返回進程的pid與當前的unix時間的總和,以保證返回一個唯一的id。
以下源碼產生一個唯一id,並寫入mbr的磁盤可選id的區域:
- int main(void)
- {
- int fd;
- unsigned int id;
- id = get_random_id();
-
- fd = open("/dev/sda", O_RDONLY);
- if (fd < 0) {
- perror("open");
- exit(1);
- }
-
- lseek(fd, 440, SEEK_SET);
- if (write(fd, &id, 4) != 4) {
- perror("write");
- close(fd);
- exit(1);
- }
- close(fd);
- return 0;
- }
這裡一定要指定4個字節,如果不確定,可能會造成越界,影響到其他區域。
保存在該區域,不會影響到MBR的正常使用,這區域本來就是保留著,可選使用。