find命令的使用方法:
"find [--set-root[=DIR]] [--devices=DEVLIST] [--ignore-floppies] [--ignore-cd] [FILENAME] [CONDITION]",
說明:
在所有設備的所有分區中搜索文件名“ FILENAME”(首先在當前啓動設備上尋找),打印包含該文件並滿足“ CONDITION”要求的設備列表。 “ CONDITION”是普通的grub命令,對於TRUE返回非零,對於FALSE返回零。
如果使用了--set-root選項,並且在設備上找到“ FILENAME”,則立即停止查找並將設備(如"(hdn,m)")設置爲新的根目錄,如果--set-root其後跟了一個路徑,如--set-root=/123/456/則根目錄需要加上這個路徑(如"(hdn,m)/123/456/")。
如果存在--ignore-floppies選項,則搜索將繞過所有軟盤,--ignore-cd將跳過CDROM。
“ DEVLIST”指定搜索設備和順序,默認的“ DEVLIST”爲“ upnhcf”。 “ DEVLIST”必須是這些字母(u,p,n,h,c,f)的組合。”u,p,n,h,c,f 分別對應 ud(udfs設備), pd(PXE設備),nd(網絡驅動器,實際已廢棄),hd(硬盤),cd(CDROM),fd(軟盤)。
示例:
find --set-root --devices=h /BOOT/BOOT10PE
在所有的硬盤上的各個分區裏尋找/BOOT/BOOT10PE文件,如果找到就將該分區作爲根設備(root)。
find命令的實現如下:
/*
arg是一行命令,flags是正在執行的環境(menu/script)
注意find命令可以在Menu下執行,也可以在"title"下執行,詳見下面"find"命令對應builtin中的flags。
*/
static int
find_func(char *arg, int flags)
{
struct builtin *builtin1 = 0;
// int ret;
char *filename;
unsigned long drive;
unsigned long tmp_drive = saved_drive;
unsigned long tmp_partition = saved_partition;
unsigned long got_file = 0;
char *set_root = 0;
unsigned long ignore_cd = 0;
unsigned long ignore_floppies = 0;
unsigned long ignore_oem = 0;
char find_devices[8] = "pnuhcf";//這是默認的尋找順序:pd->nd->ud->hd->cd->fd
//char *in_drives = NULL; /* search in drive list */
// char root_found[16];
errnum = 0;
#ifdef FSYS_FB
if (saved_drive == FB_DRIVE && !(unsigned char)(fb_status >> 8))
{
*(unsigned long *)&find_devices[3] = 0x686366;
}
#endif
/*
解析各命令行參數,"--set-root"/"--ignore-cd"/"--ignore-floppies"/"--ignore-oem"/"--devices="
root的格式類似"(%d,%d)%s".format(saved_drive, saved_partition, saved_dir),其中
saved_dir即"--set-root="之後的路徑。
*/
for (;;)
{
if (grub_memcmp(arg, "--set-root=", 11) == 0)
{
set_root = arg + 11;
if (*set_root && *set_root != ' ' && *set_root != '\t' && *set_root != '/')
return !(errnum = ERR_FILENAME_FORMAT);
}
else if (grub_memcmp(arg, "--set-root", 10) == 0)
{
set_root = "";
}
else if (grub_memcmp(arg, "--ignore-cd", 11) == 0)
{
ignore_cd = 1;
}
else if (grub_memcmp(arg, "--ignore-floppies", 17) == 0)
{
ignore_floppies = 1;
}
else if (grub_memcmp(arg, "--ignore-oem", 12) == 0)
{
ignore_oem = 1;
}
else if (grub_memcmp(arg, "--devices=", 10) == 0)
{
int i = 0;
arg += 10;
while (i < 7 && *arg >= 'a')
{
find_devices[i++] = *arg++;
}
find_devices[i] = '\0';
}
else
break;
arg = skip_to(0, arg);
}
/* 從參數中取需要查找的文件名 */
/* The filename should NOT have a DEVICE part. */
filename = set_device(arg);
if (filename)
return !(errnum = ERR_FILENAME_FORMAT);
if (*arg == '/' || *arg == '+' || (*arg >= '0' && *arg <= '9'))
{
filename = arg;
arg = skip_to(0, arg);
}
else {
filename = 0;
}
/* arg points to command. */
/* 從參數中取可選的CONDITION命令*/
if (*arg)
{
builtin1 = find_command(arg);
if ((int)builtin1 != -1)
if (!builtin1 || !(builtin1->flags & flags))
{
errnum = ERR_UNRECOGNIZED;
return 0;
}
if ((int)builtin1 != -1)
arg = skip_to(1, arg); /* get argument of command */
else
builtin1 = &builtin_command;
}
errnum = 0;
char *devtype = find_devices;
unsigned int FIND_DRIVES = 0;
/* tmp_drive保存的是當前啓動設備ID。下面這段檢測當前啓動設備
是否在--devices參數指定的設備類型列表中 */
for (; *devtype; devtype++)
{
switch (*devtype)
{
case 'h':
if (tmp_drive >= 0x80 && tmp_drive < 0xA0)
FIND_DRIVES = 1;
break;
case 'u':
if (tmp_drive == FB_DRIVE)
FIND_DRIVES = 1;
break;
case 'p':
if (PXE_DRIVE == tmp_drive)
FIND_DRIVES = 1;
break;
case 'c':
if (ignore_cd)
*devtype = ' ';
else if (current_drive == cdrom_drive || (tmp_drive >= 0xa0 && tmp_drive <= 0xff))
FIND_DRIVES = 1;
break;
case 'f':
if (ignore_floppies)
*devtype = ' ';
else if (tmp_drive < 8)
FIND_DRIVES = 1;
break;
}
}
if (FIND_DRIVES)
{
/* 如果當前啓動設備在--devices參數指定的設備類型列表中,則先在當前啓動設備下尋找文件*/
current_drive = saved_drive;
current_partition = saved_partition;
if (find_check(filename, builtin1, arg, flags) == 1)
{
got_file = 1;
if (set_root)
goto found; // 在當前啓動設備下找到了文件,那麼直接飛到found處。
}
}
/*在當前啓動設備下找不到文件時,尋找其他設備*/
for (devtype = find_devices; *devtype; devtype++)
{
current_partition = 0xFFFFFF;
switch (*devtype)
{
#ifdef FSYS_FB
case 'u':
if (fb_status)
current_drive = FB_DRIVE;
else
continue;
break;
#endif
#ifdef FSYS_PXE
case 'p':
if (pxe_entry)
current_drive = PXE_DRIVE;
else
continue;
break;
#endif
case 'c':
/* 僅在第一個CDROM下搜索文件,下面的cdrom_drive和min_cdrom_id
在common.c中的init_bios_info()中設置,見前面文章的介紹*/
if (cdrom_drive != GRUB_INVALID_DRIVE)
current_drive = cdrom_drive;
else if (atapi_dev_count)
current_drive = min_cdrom_id;
else
continue;
break;
case 'h':
case 'f':
#define FIND_HD_DRIVES (*((char *)0x475)) // 注:0x475是bios放硬盤數的地方,0x410是存放軟盤數的地方。
#define FIND_FD_DRIVES (((*(char*)0x410) & 1)?(((*(char*)0x410) >> 6) & 3 ) + 1 : 0)
FIND_DRIVES = (*devtype == 'h') ? 0x80 + FIND_HD_DRIVES : FIND_FD_DRIVES;
// 如果是硬盤則(硬盤數+0x80-1)是最後一個硬盤的ID。
// 下面這段是遍歷所有硬盤和軟盤,FIND_DRIVES等於最後一個硬盤ID加一或軟盤ID加一。
// 然後遍歷該硬盤(或軟盤)上的分區尋找文件。
for (drive = (*devtype == 'h') ? 0x80 : 0; drive < FIND_DRIVES; drive++)
{
unsigned long part = 0xFFFFFF;
unsigned long start, len, offset, ext_offset1;
unsigned long type, entry1;
saved_drive = current_drive = drive;
saved_partition = current_partition = part;
// if ((*devtype == 'f') && open_device()) //if is a partition
if (open_device()) //if is a partition
{
if ((tmp_drive != current_drive || tmp_partition != current_partition) && find_check(filename, builtin1, arg, flags) == 1)
{
got_file = 1;
if (set_root)
goto found;
}
//continue;
}
saved_drive = current_drive = drive;
while ((next_partition_drive = drive,
next_partition_dest = 0xFFFFFF,
next_partition_partition = &part,
next_partition_type = &type,
next_partition_start = &start,
next_partition_len = &len,
next_partition_offset = &offset,
next_partition_entry = &entry1,
next_partition_ext_offset = &ext_offset1,
next_partition_buf = mbr,
next_partition()))
{
if ((start == 0) || (len == 0))
continue;
if (/* type != PC_SLICE_TYPE_NONE
&& */ !(ignore_oem == 1 && (type & ~PC_SLICE_TYPE_HIDDEN_FLAG) == 0x02)
&& !IS_PC_SLICE_TYPE_BSD(type)
&& !IS_PC_SLICE_TYPE_EXTENDED(type))
{
current_drive = drive;
current_partition = part;
if ((tmp_drive != current_drive || tmp_partition != current_partition) && find_check(filename, builtin1, arg, flags) == 1)
{
got_file = 1;
if (set_root)
goto found;
}
} /*end if*/
} /*while next_partition*/
/* next_partition always sets ERRNUM in the last call, so clear it. */
errnum = ERR_NONE;
}
#undef FIND_HD_DRIVES
#undef FIND_FD_DRIVES
//h,f. no break;default continue;
default:
continue;
}
if (tmp_drive == current_drive)
continue;
if (find_check(filename, builtin1, arg, flags) == 1)
{
got_file = 1;
if (set_root)
goto found;
}
}
saved_drive = tmp_drive;
saved_partition = tmp_partition;
found:
if (got_file)
{
// 找到了文件時
errnum = ERR_NONE;
/* 通常情況下find和--set-root會一起使用。
如果--set-root後沒有跟一個路徑,則就此退出,因爲在尋找的過程中已經
設置了saved_drive和saved_partition的值。
如果使用了--set-root=,則需要將此參數指定的目錄拷貝到saved_dir。
在其他命令中定位root以如下類似格式:
"(%d,%d)%s".format(saved_drive, saved_partition, saved_dir)
*/
if (set_root)
{
int j;
/* copy root prefix to saved_dir */
for (j = 0; j < sizeof(saved_dir); j++)
{
char ch;
ch = set_root[j];
if (ch == 0 || ch == 0x20 || ch == '\t')
break;
if (ch == '\\')
{
saved_dir[j] = ch;
j++;
ch = set_root[j];
if (!ch || j >= sizeof(saved_dir))
{
j--;
saved_dir[j] = 0;
break;
}
}
saved_dir[j] = ch;
}
if (saved_dir[j - 1] == '/')
{
saved_dir[j - 1] = 0;
}
else
saved_dir[j] = 0;
} //if set_root
return 1;
}
errnum = ERR_FILE_NOT_FOUND;
return 0;
}
static struct builtin builtin_find =
{
"find",
find_func,
BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_SCRIPT | BUILTIN_HELP_LIST | BUILTIN_IFTITLE,
"find [--set-root[=DIR]] [--devices=DEVLIST] [--ignore-floppies] [--ignore-cd] [FILENAME] [CONDITION]",
"Search for the filename FILENAME in all of partitions and print the list of"
" the devices which contain the file and suffice CONDITION. CONDITION is a"
" normal grub command, which return non-zero for TRUE and zero for FALSE."
" DEVLIST specify the search devices and order,the default DEVLIST is upnhcf."
" DEVLIST must be a combination of these letters (u, p, n, h, c, f)."
" If the option --set-root is used and FILENAME is found on a device, then"
" stop the find immediately and set the device as new root."
" If the option --ignore-floppies is present, the search will bypass all"
" floppies. And --ignore-cd will skip (cd)."
};