GRUB4DOS(六) find命令的實現

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)."
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章