OS开发笔记(3)——grub-install代码阅读(基于i386-pc平台)

前言

由于安装grub到虚拟磁盘需要挂载,而挂载需要root权限,而且windows下也用不了(虽然我自己都不用Windows安装),所以我打算研究一下grub-install的代码,自己做一个简易的脚本来作为替代。


代码

读完之后再看,发现grub-install只是做了一些识别设备信息并匹配设置的准备工作,真正生成core.img的是grub-mkimage,真正负责安装的是grub-bios-setup(对于i386-pc平台)

以下代码根据我需要的目标平台i386-pc进行了删减,从而方便阅读

// 读取环境变量和命令行参数(略)

if (!grub_install_source_directory) {
    if (!target) {
        // 如果没有指定平台则使用本机信息
        const char *t;
        t = get_default_platform();
        if (!t)
            grub_util_error("%s", _("Unable to determine your platform."
                                    " Use --target."));
        target = xstrdup(t);
    }
    // 没有指定grub库目录则使用默认的
    grub_install_source_directory =
        grub_util_path_concat(2, grub_util_get_pkglibdir(), target);
}

switch (platform) {
    case GRUB_INSTALL_PLATFORM_I386_PC:
        // 对于i386-pc平台,默认使用bios引导,添加biosdisk模块
        if (!disk_module)
            disk_module = xstrdup("biosdisk");
        break;
        // 省略
}

switch (platform) {
    case GRUB_INSTALL_PLATFORM_I386_PC:
    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
        // 没有指定安装设备就报错
        if (!install_device)
            grub_util_error("%s", _("install device isn't specified"));
        break;
        // 省略
}

// 如果没有指定boot目录,使用安装设备根目录下的boot/
if (!bootdir)
    bootdir = grub_util_path_concat(3, "/", rootdir, GRUB_BOOT_DIR_NAME);

// 生成boot/grub目录的规范化路径
{
    char *t = grub_util_path_concat(2, bootdir, GRUB_DIR_NAME);
    grub_install_mkdir_p(t);
    grubdir = grub_canonicalize_file_name(t);
    if (!grubdir)
        grub_util_error(_("failed to get canonical path of `%s'"), t);
    free(t);
}
// 生成device.map文件路径
device_map = grub_util_path_concat(2, grubdir, "device.map");

if (recheck)
    // 启用recheck后如果存在device.map就删除
    grub_util_unlink(device_map);

// 检查device.map中是否有重复
device_map_check_duplicates(device_map);
// 读取device.map并注册设备
grub_util_biosdisk_init(device_map);


/* Initialize all modules. */
grub_init_all(); // (动态生成)调用所有模块的初始化函数
grub_gcry_init_all(); // 初始化加密模块
grub_hostfs_init(); // 注册本机文件系统接口
grub_host_init(); // 注册本机设备接口

switch (platform) {
    // 略
    default:
        is_efi = 0;
        break;
    // 略
}

// 对其他平台的处理,略

size_t ndev = 0;
// 尝试获取安装grub的设备
/* Write device to a variable so we don't have to traverse /dev every time. */
grub_devices = grub_guess_root_devices(grubdir);
if (!grub_devices || !grub_devices[0])
    grub_util_error(_("cannot find a device for %s (is /dev mounted?)"),
                    grubdir);

for (curdev = grub_devices; *curdev; curdev++) {
    grub_util_pull_device(*curdev); // 对于普通设备,什么也不做
    ndev++;
}

// 根据device.map获取所有设备
for (curdev = grub_devices, curdrive = grub_drives; *curdev;
     curdev++, curdrive++) {
    *curdrive = grub_util_get_grub_dev(*curdev);
    if (!*curdrive)
        grub_util_error(
        _("cannot find a GRUB drive for %s.  Check your device.map"),
        *curdev);
}
*curdrive = 0;

// 打开设备
grub_dev = grub_device_open(grub_drives[0]);
if (!grub_dev)
    grub_util_error("%s", grub_errmsg);
// 探测文件系统
grub_fs = grub_fs_probe(grub_dev);
if (!grub_fs)
    grub_util_error("%s", grub_errmsg);
// 添加文件系统需要的模块
grub_install_push_module(grub_fs->name);
// 探测安装grub的磁盘需要的模块
if (grub_dev->disk)
    probe_mods(grub_dev->disk);
// 为其他磁盘探测需要的模块
for (curdrive = grub_drives + 1; *curdrive; curdrive++) {
    grub_device_t dev = grub_device_open(*curdrive);
    if (!dev)
        continue;
    if (dev->disk)
        probe_mods(dev->disk);
    grub_device_close(dev);
}
// 补充需要的加密、驱动模块和参数输入的模块,略

// 将boot/grub/从相对路径转换成绝对路径
relative_grubdir = grub_make_system_path_relative_to_its_root(grubdir);
if (relative_grubdir[0] == '\0') {
    free(relative_grubdir);
    relative_grubdir = xstrdup("/");
}

char *prefix_drive = NULL;
char *install_drive = NULL;

if (install_device) {
    if (install_device[0] == '(' &&
        install_device[grub_strlen(install_device) - 1] == ')') {
        // 如果有指定安装设备则将install_drive设为指定的设备
        size_t len = grub_strlen(install_device) - 2;
        install_drive = xmalloc(len + 1);
        memcpy(install_drive, install_device + 1, len);
        install_drive[len] = '\0';
    } else {
        // 没有指定则自动获取
        grub_util_pull_device(install_device);
        install_drive = grub_util_get_grub_dev(install_device);
        if (!install_drive)
            grub_util_error(
            _("cannot find a GRUB drive for %s.  Check your device.map"),
            install_device);
    }
}
// 把grub的文件都复制进去
grub_install_copy_files(grub_install_source_directory, grubdir, platform);

// 创建grub运行时的环境变量文件
char *envfile = grub_util_path_concat(2, grubdir, "grubenv");
if (!grub_util_is_regular(envfile))
    grub_util_create_envblk_file(envfile);

// 生成平台文件夹路径,例如boot/grub/i386-pc/
char *platname = grub_install_get_platform_name(platform);
char *platdir;
{
    char *t = grub_util_path_concat(2, grubdir, platname);
    platdir = grub_canonicalize_file_name(t);
    if (!platdir)
        grub_util_error(_("failed to get canonical path of `%s'"), t);
    free(t);
}

// 删除load.cfg
load_cfg = grub_util_path_concat(2, platdir, "load.cfg");
grub_util_unlink(load_cfg);

if (!have_abstractions) {
    // 有抽象层,可能意味着有文件系统?
	if ((disk_module && grub_strcmp(disk_module, "biosdisk") != 0) // 可通过非BIOS调用管理的磁盘
        || grub_drives[1] // 有多个磁盘
        || (!install_drive && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) 
        || (install_drive && !is_same_disk(grub_drives[0], install_drive)) // 要安装到的磁盘不是第一个磁盘
        || !have_bootdev(platform) // 对于i386-pc,have_bootdev的返回为1,所以可以忽略
       ) {
        char *uuid = NULL;
        /*  generic method (used on coreboot and ata mod).  */
        if (!force_file_id // 如果为指定force_file_id
            && grub_fs->fs_uuid // 有生成uuid的实现
            && grub_fs->fs_uuid(grub_dev, &uuid) // 成功生成uuid
           ) {
            grub_print_error();
            grub_errno = 0;
            uuid = NULL;
        }
        
        // 如果没有load.cfg就创建新的
        if (!load_cfg_f)
            load_cfg_f = grub_util_fopen(load_cfg, "wb");
        have_load_cfg = 1;
        if (uuid) {
            // 有uuid则配置为根据uuid搜索grub所在的分区
            fprintf(load_cfg_f, "search.fs_uuid %s root ", uuid);
            grub_install_push_module("search_fs_uuid");
        } else {
            // 无uuid则生成一个标识文件用于定位
            char *rndstr = get_rndstr();
            char *fl = grub_util_path_concat(3, grubdir, "uuid", rndstr);
            char *fldir = grub_util_path_concat(2, grubdir, "uuid");
            char *relfl;
            FILE *flf;
            grub_install_mkdir_p(fldir);
            flf = grub_util_fopen(fl, "w");
            if (!flf)
                grub_util_error(_("Can't create file: %s"), strerror(errno));
            fclose(flf);
            relfl = grub_make_system_path_relative_to_its_root(fl);
            fprintf(load_cfg_f, "search.file %s root ", relfl);
            grub_install_push_module("search_fs_file");
        }
        // 循环添加所有磁盘设备到load.cfg中,略
        fprintf(load_cfg_f, "\n"); // 搜索命令结束
        
        // 设定环境变量命令,指定grub目录位置
        char *escaped_relpath = escape(relative_grubdir);
        fprintf(load_cfg_f, "set prefix=($root)'%s'\n", escaped_relpath);
	} else {
        // 对于其他磁盘,硬编码分区号到core映像中
        /* We need to hardcode the partition number in the core image's prefix. */
        char *p;
        for (p = grub_drives[0]; *p;) {
            // 跳过转义字符
            if (*p == '\\' && p[1]) {
                p += 2;
                continue;
            }
            // 遇到分隔符或结束
            if (*p == ',' || *p == '\0')
                break;
            p++;
        }
        prefix_drive = xasprintf("(%s)", p);
    }
} else {
    // 启用加密时的处理,略
    
    // 直接复制驱动器号
    prefix_drive = xasprintf("(%s)", grub_drives[0]);
}

// 调用grub-mkimage生成core.img,略

switch (platform) {
    case GRUB_INSTALL_PLATFORM_I386_PC: {
        // 复制boot.img到grub平台目录
        char *boot_img_src =
            grub_util_path_concat(2, grub_install_source_directory, "boot.img");
        char *boot_img = grub_util_path_concat(2, platdir, "boot.img");
        grub_install_copy_file(boot_img_src, boot_img, 1);

        // 中间略

        /*  Now perform the installation.  */
        if (install_bootsector) {
            // 调用grub-bios-setup安装编译好的boot.img和刚生成的core.img
            grub_util_bios_setup(platdir, "boot.img", "core.img", install_drive,
                                 force, fs_probe, allow_floppy, add_rs_codes,
                                 !grub_install_is_short_mbrgap_supported());

            grub_set_install_backup_ponr();
        }
        break;
    }
    // 其他平台略
}

// 结束部分
/*
 * Either there are no platform specific code, or it didn't raise
 * ponr. Raise it here, because usually this is already past point
 * of no return. If we leave this flag false, at exit all the modules
 * will be removed from the prefix which would be very confusing.
 */
grub_set_install_backup_ponr();

fprintf(stderr, "%s\n", _("Installation finished. No error reported."));

/* Free resources.  */
grub_gcry_fini_all();
grub_fini_all();
posted @   迷路的鹿1202  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示