update-grub脚本分析

假如/boot目录下面有多个内核(例如kernel1、kernel2、kernel3等),你现在运行内核版本是kernel1运行update-grub命令之后,你会发现grub.cfg文件的默认启动项被更改为启动kernel3,这样如果你重启系统,系统就会切换到运行内核kernel3上面

发现这种现象是在修改了/boot/default/grub文件中的选项之后,运行update-grub命令发现的。所改动的无非是增加cmdline的命令行选项,为何会引起grub启动menuentry改变呢?


update-grub脚本内容如下:

#!/bin/sh

set -e

exec grub-mkconfig -o /boot/grub/grub.cfg "$@"

脚本很简单,就是调用grub-mkconfig命令。grub-mkconfig也是一个bash脚本,它就是用来生成grub.cfg文件的。

grub-mkconfig代码片段:


253---263行就是在grub.cfg文件开头看到的注释部分。grub_mkconfig_dir变量就是/etc/grub.d目录${sysconfdir}/default/grub对应就是/etc/default/grub,注释部分的意思就是生成grub.cfg启动项是使用/etc/grub.d目录下的模板生成的,默认的一些配置,包括命令行选项、默认启动等待时间默认启动项等设置是从读取/etc/default/grub文件。

266---281行for循环中就是遍历/etc/grub.d目录下的模板文件。先看下/etc/grub.d目录下有哪些文件

/etc/grub.d/

├── 00_header

├── 05_debian_theme

├── 10_linux

├── 20_linux_xen

├── 30_os-prober

├── 30_uefi-firmware

├── 40_custom

├── 41_custom

└── README

273行的grub_file_is_not_garbage函数在/usr/share/grub/grub-mkconfig_lib文件中实现,在这里传进来的参数就是上面看到的/etc/grub.d目录下的文件。这一行就是找出此目录下具有执行权限的文件。

for循环就是执行/etc/grub.d目录下具有可执行权限的文件。分析这些文件及结合grub.cfg内容,不难发现生成grub.cfg文件启动menuentry10_linux文件中。


10_linux文件代码片段:


这段代码主要就是遍历/boot目录或者/目录下的文件,并将它们保存在list变量中。


276is_top_level变量是用来标记区分menuentrysubmenuentry

277开始的while循环变量前面保存的list也就是系统中的各种版本的内核文件

278行调用version_find_latest函数取出此list版本号latest的内核,并赋给变量linux

version_find_latest函数/usr/share/grub/grub-mkconfig_lib文件中实现

version_test_gt ()

{

  version_test_gt_sedexp="s/[^-]*-//;s/[._-]\(pre\|rc\|test\|git\|old\|trunk\)/~\1/g"

  version_test_gt_a="`echo "$1" | sed -e "$version_test_gt_sedexp"`"

  version_test_gt_b="`echo "$2" | sed -e "$version_test_gt_sedexp"`"

  version_test_gt_cmp=gt

  if [ "x$version_test_gt_b" = "x" ] ; then

    return 0

  fi

  case "$version_test_gt_a:$version_test_gt_b" in

    *.old:*.old) ;;

    *.old:*) version_test_gt_a="`echo -n "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;;

    *:*.old) version_test_gt_b="`echo -n "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;;

  esac

  dpkg --compare-versions "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b"

  return "$?"

}

 

version_find_latest ()

{

  version_find_latest_a=""

  for i in "$@" ; do

    if version_test_gt "$i" "$version_find_latest_a" ; then

      version_find_latest_a="$i"

    fi

  done

  echo "$version_find_latest_a"

}

version_find_latest函数调用version_test_gt函数找出list列出的所有版本内核中最新的内核。version_test_gt函数首先将传进来的两个参数(内核文件名)取出版本号子字符例如传进来内核/boot/vmlinuz-3.16.0-4-amd64和/boot/vmlinuz-3.16.7-ckt7,那么取出来的版本子字符就是3.16.0-4-amd64和3.16.7-ckt7,然后调用dpkg --compare-versions来比较两个之间版本号比较大的一个


回到277开始for循环,此循环就是照版本号从大到小生grub.cfg文件中的各个内核启动项。接下来看看具体某个版本内核的启动项是如何生死的,例如系统中有两个版本的内核:/boot/vmlinuz-3.16.0-4-amd64和/boot/vmlinuz-3.16.7-ckt7,那么运行278行取出来的最新版本内核就是/boot/vmlinuz-3.16.7-ckt7,linux=”/boot/vmlinuz-3.16.7-ckt7”


287行:basename=vmlinuz-3.16.7-ckt7

288行:dirname=/boot

289行:rel_dirname=/boot

290行version=3.16.7-ckt7

291行alt_version=3.16.7-ckt7

292行linux_root_device_thisversion=



295~307行是一个for循环,它是用来在dirname目录下查找version版本对应的initrd文件系统例如/boot/vmlinuz-3.16.7-ckt7文件系统,对应的文件系统

initrd=initrd.img-3.16.7-ckt7



309~315行for循环是用来查找version版本内核对应的内核CONFIG选项的config文件,这里config=/boot/config-3.16.7-ckt7


  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值