grub2공식 매뉴얼 대부분을 번역한 후 직접 정리했습니다. 내용이 다소 복잡하기 때문에 장의 배열이 그다지 합리적이지 않을 수 있으니 양해해 주시기 바랍니다.
이 문서의 디렉터리:
1.1 기본 콘텐츠
1.2 grub2
1.3 설치 grub 2 구성 파일
1.4 명령줄 및 메뉴 항목
1.5의 명령 몇 가지 일반적인 내장 변수
1.6 grub 구성 및 설치 예
1.7 기존 grub에 대한 간략한 소개
이것은 기사가 주로 소개하는 것이 grub2입니다. 기사 마지막에는 Traditional Grub에 대해 간략하게 설명하고 있지만, grub2의 내용에는 grub2와 Traditional Grub의 비교 내용이 많이 포함되어 있습니다.
grub2의 boot.img/core.img/diskboot.img/kernel.img 또는 기존 grub의 stage1/stage1_5/stage2 파일의 역할을 알고 싶다면 관련 항목으로 직접 이동하세요. content 읽어보세요.
공식 매뉴얼 원문:
몇 가지 주요 내용만 설명:
1. ~의 구성 파일이 변경되었습니다. grub에서 구성 파일은 grub.conf 또는 menu.lst(grub.conf에 대한 소프트 링크)이고 grub2에서는 grub.cfg로 이름이 변경되었습니다.
2.grub2에는 지원 변수, 조건부 판단, 루프 등 스크립팅 언어에 가까운 구문이 많이 추가되었습니다.
3. grub2에서는 장치 이름이 1부터 시작하지만 grub에서는 0부터 시작합니다.
4.grub2는 img 파일을 사용하며 더 이상 grub에서 stage1, stage1.5 및 stage2를 사용하지 않습니다.
5 grub을 구성하려면 그래픽 인터페이스를 지원하지만 epel 소스에서 제공하는 grub-customizer 패키지를 설치해야 합니다.
6. 운영 체제 환경에 들어가면 더 이상 grub 명령이 제공되지 않습니다. 즉, 컴퓨터가 부팅될 때만 grub 대화형 인터페이스에 들어갈 수 있다는 것이 큰 단점입니다.
7. grub2에는 유용한 find 명령이 없으며 이는 또 다른 주요 단점입니다.命1.1.2 명명 습관 및 파일 경로 표현
R
(fd0) :表示第一块软盘 (hd0,msdos2) :表示第一块硬盘的第二个mbr分区。grub2中分区从1开始编号,传统的grub是从0开始编号的 (hd0,msdos5) :表示第一块硬盘的第一个逻辑分区 (hd0,gpt1) :表示第一块硬盘的第一个gpt分区/boot/vmlinuz :相对路径,基于根目录,表示根目录下的boot目录下的vmlinuz, :如果设置了根目录变量root为(hd0,msdos1),则表示(hd0,msdos1)/boot/vmlinuz (hd0,msdos1)/boot/vmlinuz:绝对路径,表示第一硬盘第一分区的boot目录下的vmlinuz文件
Grub2 지원 2 운영 체제 부팅 방법:
1.1.4 grub2 프로그램 및 기존 grub 프로그램 설치 후 파일 배포
[root@xuexi ~]# ls /usr/share/grub/x86_64-redhat/e2fs_stage1_5 ffs_stage1_5 jfs_stage1_5 reiserfs_stage1_5 stage2 ufs2_stage1_5 xfs_stage1_5 fat_stage1_5 iso9660_stage1_5 minix_stage1_5 stage1 stage2_eltorito vstafs_stage1_5
grub2 소프트웨어가 설치된 후 일부 lst 목록 파일을 포함한 많은 모듈 파일과 img 파일이 /usr/lib/grub/i386-pc/ 디렉터리에 생성됩니다.
[root@server7 ~]# ls /usr/lib/grub/i386-pc/*.mod | wc -l257[root@server7 ~]# ls -lh /usr/lib/grub/i386-pc/*.lst -rw-r--r--. 1 root root 3.7K Nov 24 2015 /usr/lib/grub/i386-pc/command.lst -rw-r--r--. 1 root root 936 Nov 24 2015 /usr/lib/grub/i386-pc/crypto.lst -rw-r--r--. 1 root root 214 Nov 24 2015 /usr/lib/grub/i386-pc/fs.lst -rw-r--r--. 1 root root 5.1K Nov 24 2015 /usr/lib/grub/i386-pc/moddep.lst -rw-r--r--. 1 root root 111 Nov 24 2015 /usr/lib/grub/i386-pc/partmap.lst -rw-r--r--. 1 root root 17 Nov 24 2015 /usr/lib/grub/i386-pc/parttool.lst -rw-r--r--. 1 root root 202 Nov 24 2015 /usr/lib/grub/i386-pc/terminal.lst -rw-r--r--. 1 root root 33 Nov 24 2015 /usr/lib/grub/i386-pc/video.lst[root@server7 ~]# ls -lh /usr/lib/grub/i386-pc/*.img-rw-r--r--. 1 root root 512 Nov 24 2015 /usr/lib/grub/i386-pc/boot_hybrid.img -rw-r--r--. 1 root root 512 Nov 24 2015 /usr/lib/grub/i386-pc/boot.img -rw-r--r--. 1 root root 2.0K Nov 24 2015 /usr/lib/grub/i386-pc/cdboot.img -rw-r--r--. 1 root root 512 Nov 24 2015 /usr/lib/grub/i386-pc/diskboot.img -rw-r--r--. 1 root root 28K Nov 24 2015 /usr/lib/grub/i386-pc/kernel.img -rw-r--r--. 1 root root 1.0K Nov 24 2015 /usr/lib/grub/i386-pc/lnxboot.img -rw-r--r--. 1 root root 2.9K Nov 24 2015 /usr/lib/grub/i386-pc/lzma_decompress.img -rw-r--r--. 1 root root 1.0K Nov 24 2015 /usr/lib/grub/i386-pc/pxeboot.img
当使用grub来管理启动菜单时,那么boot loader都是grub程序安装的。
传统的grub将stage1转换后的内容安装到MBR(VBR或EBR)中的boot loader部分,将stage1_5转换后的内容安装在紧跟在MBR后的扇区中,将stage2转换后的内容安装在/boot分区中。
grub2将boot.img转换后的内容安装到MBR(VBR或EBR)中的boot loader部分,将diskboot.img和kernel.img结合成为core.img,同时还会嵌入一些模块或加载模块的代码到core.img中,然后将core.img转换后的内容安装到磁盘的指定位置处。
它们之间更具体的关系见下文。
官方手册原文:
严格地说是core.img的安装位置,因为boot.img的位置是固定在MBR或VBR或EBR上的。
(1).MBR
MBR格式的分区表用于PC BIOS平台,这种格式允许四个主分区和额外的逻辑分区。使用这种格式的分区表,有两种方式安装GURB:
嵌入到MBR和第一个分区中间的空间,这部分就是大众所称的"boot track","MBR gap"或"embedding area",它们大致需要31kB的空间;
将core.img安装到某个文件系统中,然后使用分区的第一个扇区(严格地说不是第一个扇区,而是第一个block)存储启动它的代码。
这两种方法有不同的问题。
使用嵌入的方式安装grub,就没有保留的空闲空间来保证安全性,例如有些专门的软件就是使用这段空间来实现许可限制的;另外分区的时候,虽然会在MBR和第一个分区中间留下空闲空间,但可能留下的空间会比这更小。
方法二安装grub到文件系统,但这样的grub是脆弱的。例如,文件系统的某些特性需要做尾部包装,甚至某些fsck检测,它们可能会移动这些block。
GRUB开发团队建议将GRUB嵌入到MBR和第一个分区之间,除非有特殊需求,但仍必须要保证第一个分区至少是从第31kB(第63个扇区)之后才开始创建的。
现在的磁盘设备,一般都会有分区边界对齐的性能优化提醒,所以第一个分区可能会自动从第1MB处开始创建。
(2).GPT
一些新的系统使用GUID分区表(GPT)格式,这种格式是EFI固件所指定的一部分。但如果操作系统支持的话,GPT也可以用于BIOS平台(即MBR风格结合GPT格式的磁盘),使用这种格式,需要使用独立的BIOS boot分区来保存GRUB,GRUB被嵌入到此分区,不会有任何风险。
当在gpt磁盘上创建一个BIOS boot分区时,需要保证两件事:(1)它最小是31kB大小,但一般都会为此分区划分1MB的空间用于可扩展性;(2)必须要有合理的分区类型标识(flag type)。
例如使用gun parted工具时,可以设置为bios_grub标识:
# parted /dev/sda toggle partition_num bios_grub # parted /dev/sda set partiton_num bios_grub on
如果使用gdisk分区工具时,则分类类型设置为"EF02"。
如果使用其他的分区工具,可能需要指定guid,则可以指定其guid为"21686148-6449-6e6f-744e656564454649"。
下图是某个bios/gpt格式的bios boot分区信息,从中可见,它大小为1M,没有文件系统,分区表示为bios_grub。
下图为gpt磁盘在图形界面下安装操作系统时创建的Bios boot分区。
在传统的grub上,可以直接在bash下敲入grub命令进入命令交互模式,但grub2只能在系统启动前进入grub交互命令行。
按下e见可以编辑所选菜单对应的grub菜单配置项,按下c键可以进入grub命令行交互模式。
官方手册原文:
这里的安装指的不是安装grub程序,而是安装Boot loader,但一般都称之为安装grub,且后文都是这个意思。
安装方式非常简单,只需调用grub2-install,然后给定安装到的设备名即可。
shell> grub2-install /dev/sda
这样的安装方式,默认会将img文件放入到/boot目录下,如果想自定义放置位置,则使用--boot-directory选项指定,可用于测试练习grub的时候使用,但在真实的grub环境下不建议做任何改动。
shell> grub2-install --boot-director=/mnt/boot /dev/fd0
如果是EFI固件平台,则必须挂载好efi系统分区,一般会挂在/boot/efi下,这是默认的,此时可直接使用grub2-install安装。
shell> grub2-install
如果不是挂载在/boot/efi下,则使用--efi-directory指定efi系统分区路径。
shell> grub2-install --efi-directory=/mnt/efi
grub2-install은 실제로 다른 도구를 호출하는 데 사용되는 쉘 스크립트입니다. 실제 기능은 다른 도구에 의해 완료되므로 grub 내부 명령 및 메커니즘에 매우 익숙하다면 grub2-install이 전혀 필요하지 않습니다.
해당 기존 grub 설치 명령은 grub-install이며 사용법은 grub2-install과 동일합니다.
공식 매뉴얼 원문:
Img 파일은 grub2에 의해 생성되고 스테이지 파일은 기존 grub에 의해 생성됩니다. 다음은 다양한 파일에 대한 설명입니다.
grub2의 img 파일은 여러 img 파일을 생성했으며 일부는 /usr/lib/grub/i386-pc 디렉터리에 배포되고 일부는 /boot/grub2/i386-pc 디렉터리에 배포됩니다. 다음 내용을 읽고 나면 이들 사이의 관계를 이해하게 되리라 믿습니다.
다음 그림은 다양한 img 파일 간의 관계를 설명합니다. 그 중 core.img는 동적으로 생성되며, 경로는 /boot/grub2/i386-pc/core.img이고, 다른 img는 /usr/lib/grub/i386-pc 디렉터리에 존재합니다. 물론 grub을 설치하면 boot.img가 /boot/grub2/i386-pc 디렉토리에 복사됩니다.
(1)boot.img
BIOS 플랫폼에서 boot.img는 grub이 시작한 첫 번째 img 파일입니다. 부팅 크기 때문에 MBR이나 파티션의 부팅 섹터에 기록됩니다. 섹터가 512바이트이므로 img 파일의 크기도 512바이트입니다.
boot.img의 유일한 기능은 core.img에 속한 첫 번째 섹터를 읽고 점프하여 해당 섹터의 img에 제어권을 주는 것입니다. 크기 제한으로 인해 boot.img는 파일 시스템의 구조를 이해할 수 없으므로 grub2-install은 core.img의 위치를 boot.img에 하드 코딩하여 core.img의 위치를 찾을 수 있습니다.
(2)core.img
core.img는 diskboot.img, kernel.img 및 일련의 모듈을 기반으로 하는 grub2-mkimage 프로그램에 의해 동적으로 생성됩니다. grub이 /boot/grub에 액세스할 수 있도록 core.img에 충분한 기능 모듈이 내장되어 있으며, 관련 모듈을 로드하여 부팅 메뉴 로드, 대상 운영 체제에 대한 정보 로드 등과 같은 관련 기능을 구현할 수 있습니다. grub2가 광범위하게 사용됩니다. 동적 함수 모듈은 core.img의 크기를 충분히 작게 만듭니다.
core.img에는 diskboot.img/kernel.img 등을 포함한 여러 img 파일의 내용이 포함되어 있습니다.
core.img의 설치 위치는 위에서 설명한 MBR 디스크와 GPT 디스크에 따라 다릅니다.
(3)diskboot.img
부팅 장치가 하드 디스크인 경우, 즉 하드 디스크에서 부팅할 때 core.img의 첫 번째 섹터 내용은 diskboot.img입니다. diskboo.img의 기능은 core.img의 나머지 부분을 메모리로 읽고 제어권을 kernel.img로 전달하는 것입니다. 현재 파일 시스템이 인식되지 않으므로 core.img의 모든 위치가 차단 목록에 나열됩니다. diskboot.img가 나머지 콘텐츠를 찾을 수 있도록 인코딩됩니다.
img 파일은 한 섹터를 차지하기 때문에 크기는 512바이트입니다.
(4)cdboot.img
부팅 장치가 CD-ROM 드라이브인 경우, 즉 CD-ROM 드라이브에서 부팅할 때 core.img의 첫 번째 섹터 내용은 cdboo.img입니다. 기능은 diskboot.img와 동일합니다.
(5)pexboot.img
네트워크의 PXE 환경에서 부팅하는 경우 core.img의 첫 번째 섹터 내용은 pxeboot.img입니다.
(6)kernel.img
kernel.img 파일에는 장치 프레임워크, 파일 핸들, 환경 변수, 복구 모드의 명령줄 파서 등 grub의 기본 런타임 환경이 포함되어 있습니다. core.img에 완전히 포함되어 있기 때문에 직접적으로 사용되는 경우는 거의 없습니다. kernel.img는 grub의 커널이며 운영 체제의 커널과 아무 관련이 없습니다.
조심해 보면 kernel.img 자체는 28KB의 공간을 차지하지만 core.img에 포함된 후에는 core.img 파일의 크기가 26KB에 불과하다는 것을 알 수 있습니다. 이는 core.img의 kernel.img가 압축되어 있기 때문입니다.
(7)lnxboot.img
img 파일은 core.img 앞에 배치되어 grub을 Linux 커널처럼 만들어 LILO의 "image="에서 core.img를 인식할 수 있도록 합니다. 물론 이것은 LILO와 함께 사용되지만 현재 누가 아직도 LILO를 사용하고 있습니까?
(8)*.mod
다양한 기능 모듈 중 일부는 core.img에 포함되어 있거나 grub에 의해 자동으로 로드되지만 때로는 insmod 명령을 사용하여 수동으로 로드해야 할 수도 있습니다.
grub2的设计方式和传统grub大不相同,因此和stage之间的对比关系其实没那么标准,但是将它们拿来比较也有助于理解img和stage文件的作用。
stage文件也分布在两个地方:/usr/share/grub/RELEASE目录下和/boot/grub目录下,/boot/grub目录下的stage文件是安装grub时从/usr/share/grub/RELEASE目录下拷贝过来的。
(1)stage1
stage1文件在功能上等价于boot.img文件。目的是跳转到stage1_5或stage2的第一个扇区上。
(2)*_stage1_5
*stage1_5文件包含了各种识别文件系统的代码,使得grub可以从文件系统中读取体积更大功能更复杂的stage2文件。从这一方面考虑,它类似于core.img中加载对应文件系统模块的代码部分,但是core.img的功能远比stage1_5多。
stage1_5一般安装在MBR后、第一个分区前的那段空闲空间中,也就是MBR gap空间,它的作用是跳转到stage2的第一个扇区。
其实传统的grub在某些环境下是可以不用stage1_5文件就能正常运行的,但是grub2则不能缺少core.img。
(3)stage2
stage2的作用是加载各种环境和加载内核,在grub2中没有完全与之相对应的img文件,但是core.img中包含了stage2的所有功能。
当跳转到stage2的第一个扇区后,该扇区的代码负责加载stage2剩余的内容。
注意,stage2是存放在磁盘上的,并没有像core.img一样嵌入到磁盘上。
(4)stage2_eltorito
功能上等价于grub2中的core.img中的cdboot.img部分。一般在制作救援模式的grub时才会使用到cd-rom相关文件。
(5)pxegrub
功能上等价于grub2中的core.img中的pxeboot.img部分。
安装grub2的过程大体分两步:一是根据/usr/lib/grub/i386-pc/目录下的文件生成core.img,并拷贝boot.img和core.img涉及的某些模块文件到/boot/grub2/i386-pc/目录下;二是根据/boot/grub2/i386-pc目录下的文件向磁盘上写boot loader。
当然,到底是先拷贝,还是先写boot loader,没必要去搞清楚,只要/boot/grub2/i386-pc下的img文件一定能通过grub2相关程序再次生成boot loader。所以,既可以认为/boot/grub2/i386-pc目录下的img文件是boot loader的特殊备份文件,也可以认为是boot loader的源文件。
不过,img文件和boot loader的内容是不一致的,因为img文件还要通过grub2相关程序来转换才是真正的boot loader。
对于传统的grub而言,拷贝的不是img文件,而是stage文件。
以下是安装传统grub时,grub做的工作。很不幸,grub2上没有该命令,也没有与之等价的命令。
grub> setup (hd0) Checking if "/boot/grub/stage1" exists... yes Checking if "/boot/grub/stage2" exists... yes Checking if "/boot/grub/e2fs_stage1_5" exists... yes Running "embed /boot/grub/e2fs_stage1_5 (hd0)"... 15 sectors are embedded. succeeded Running "install /boot/grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded Done.
首先检测各stage文件是否存在于/boot/grub目录下,随后嵌入stage1_5到磁盘上,该文件系统类型的stage1_5占用了15个扇区,最后安装stage1,并告知stage1 stage1_5的位置是第1到第15个扇区,之所以先嵌入stage1_5再嵌入stage1就是为了让stage1知道stage1_5的位置,最后还告知了stage1 stage2和配置文件menu.lst的路径。
grub2的默认配置文件为/boot/grub2/grub.cfg,该配置文件的写法弹性非常大,但绝大多数需要修改该配置文件时,都只需修改其中一小部分内容就可以达成目标。
grub2-mkconfig程序可用来生成符合绝大多数情况的grub.cfg文件,默认它会自动尝试探测有效的操作系统内核,并生成对应的操作系统菜单项。使用方法非常简单,只需一个选项"-o"指定输出文件即可。
shell> grub2-mkconfig -o /boot/grub2/grub.cfg
官方手册原文:
grub2-mkconfig是根据/etc/default/grub文件来创建配置文件的。该文件中定义的是grub的全局宏,修改内置的宏可以快速生成grub配置文件。实际上在/etc/grub.d/目录下还有一些grub配置脚本,这些shell脚本读取一些脚本配置文件(如/etc/default/grub),根据指定的逻辑生成grub配置文件。若有兴趣,不放读一读/etc/grub.d/10_linux文件,它指导了创建grub.cfg的细节,例如如何生成启动菜单。
[root@xuexi ~]# ls /etc/grub.d/00_header 00_tuned 01_users 10_linux 20_linux_xen 20_ppc_terminfo 30_os-prober 40_custom 41_custom README
在/etc/default/grub中,使用"key=vaule"的格式,key全部为大小字母,如果vaule部分包含了空格或其他特殊字符,则需要使用引号包围。
例如,下面是一个/etc/default/grub文件的示例:
[root@xuexi ~]# cat /etc/default/grubGRUB_TIMEOUT=5GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=trueGRUB_TERMINAL_OUTPUT="console"GRUB_CMDLINE_LINUX="crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet"GRUB_DISABLE_RECOVERY="true"
虽然可用的宏较多,但可能用的上的就几个:GRUB_DEFAULT、GRUB_TIMEOUT、GRUB_CMDLINE_LINUX和GRUB_CMDLINE_LINUX_DEFAULT。
以下列出了部分key。
(1).GRUB_DEFAULT
默认的菜单项,默认值为0。其值可为数值N,表示从0开始计算的第N项是默认菜单,也可以指定对应的title表示该项为默认的菜单项。使用数值比较好,因为使用的title可能包含了容易改变的设备名。例如有如下菜单项:
menuentry 'Example GNU/Linux distribution' --class gnu-linux --id example-gnu-linux { ... }로그인 후 복사
如果想将此菜单设为默认菜单,则可设置"GRUB_DEFAULT=example-gnu-linux"。
如果GRUB_DEFAULT的值设置为"saved",则表示默认的菜单项是"GRUB_SAVEDEFAULT"或"grub-set-default"所指定的菜单项。
(2).GRUB_SAVEDEFAULT
默认该key的值未设置。如果该key的值设置为true时,如果选定了某菜单项,则该菜单项将被认为是新的默认菜单项。该key只有在设置了"GRUB_DEFAULT=saved"时才有效。
不建议使用该key,因为GRUB_DEFAULT配合grub-set-default更方便。
(3).GRUB_TIMEOUT
在开机选择菜单项的超时时间,超过该时间将使用默认的菜单项来引导对应的操作系统。默认值为5秒。等待过程中,按下任意按键都可以中断等待。
设置为0时,将不列出菜单直接使用默认的菜单项引导与之对应的操作系统,设置为"-1"时将永久等待选择。
是否显示菜单,和"GRUB_TIMEOUT_STYLE"的设置有关。
(4).GRUB_TIMEOUT_STYLE
如果该key未设置值或者设置的值为"menu",则列出启动菜单项,并等待"GRUB_TIMEOUT"指定的超时时间。
如果设置为"countdown"和"hidden",则不显示启动菜单项,而是直接等待"GRUB_TIMEOUT"指定的超时时间,如果超时了则启动默认菜单项并引导对应的操作系统。在等待过程中,按下"ESC"键可以列出启动菜单。设置为countdown和hidden的区别是countdown会显示超时时间的剩余时间,而hidden则完全隐藏超时时间。
(5).GRUB_DISTRIBUTOR
设置发行版的标识名称,一般该名称用来作为菜单的一部分,以便区分不同的操作系统。
(6).GRUB_CMDLINE_LINUX
添加到菜单中的内核启动参数。例如:
GRUB_CMDLINE_LINUX="crashkernel=ro root=/dev/sda3 biosdevname=0 net.ifnames=0 rhgb quiet"
(7).GRUB_CMDLINE_LINUX_DEFAULT
除非"GRUB_DISABLE_RECOVERY"设置为"true",否则该key指定的默认内核启动参数将生成两份,一份是用于默认启动参数,一份用于恢复模式(recovery mode)的启动参数。
该key生成的默认内核启动参数将添加在"GRUB_CMDLINE_LINUX"所指定的启动参数之后。
(8).GRUB_DISABLE_RECOVERY
该项设置为true时,将不会生成恢复模式的菜单项。
(9).GRUB_DISABLE_LINUX_UUID
默认情况下,grub2-mkconfig在生产菜单项的时候将使用uuid来标识Linux 内核的根文件系统,即"root=UUID=..."。
例如,下面是/boot/grub2/grub.cfg中某菜单项的部分内容。
menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8' {
......
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto biosdevname=0 net.ifnames=0 quiet LANG=en_US.UTF-8
initrd16 /initramfs-3.10.0-327.el7.x86_64.img
}
虽然使用UUID的方式更可靠,但有时候不太方便,所以可以设置该key为true来禁用。
(10).GRUB_BACKGROUND
배경 이미지를 설정하세요. 배경 이미지는 grub에서 읽을 수 있어야 합니다. 이미지 파일 이름 접미사는 ".png", ".jpg", ".jpeg"여야 합니다. 화면 크기에 맞게 이미지를 조정합니다.
(11).GRUB_THEME
grub 메뉴의 테마를 설정합니다.
(12).GRUB_GFXPAYLOAD_LINUX
"text"로 설정하면 Linux가 강제로 텍스트 모드에서 시작됩니다. 경우에 따라 그래픽 모드가 지원되지 않을 수 있습니다.
(13).GRUB_DISABLE_OS_PROBER
기본적으로 grub2-mkconfig는 os-prober 프로그램(이미 설치되어 있는 경우 기본적으로 설치해야 함)을 사용하여 사용 가능한 다른 운영 체제 커널을 검색하고 해당 시작을 생성합니다. 메뉴 항목입니다. 자동 감지를 비활성화하려면 "true"로 설정합니다.
(14).GRUB_DISABLE_SUBMENU
기본적으로 grub2-mkconfig가 동일한 버전 또는 하위 버전의 여러 커널을 찾으면 가장 높은 버전의 커널 및 기타 모든 하위 버전에 대한 최상위 메뉴만 생성합니다. 커널 메뉴가 하위 메뉴에 배치되며 모두 최상위 메뉴로 생성하려면 "y"로 설정합니다.
(15).GRUB_HIDDEN_TIMEOUT(더 이상 사용되지 않지만 이전 버전과의 호환성을 위해 여전히 유효함)
대신 "GRUB_TIMEOUT_STYLE={countdown|hidden}"을 사용하세요.
(16).GRUB_HIDDEN_TIMEOUT_QUIET(더 이상 사용되지 않지만 여전히 이전 버전과의 호환성을 위해 유효함) 호환 가능, 여전히 유효)
GRUB_HIDDEN_TIMEOUT과 함께 사용하면 GRUB_TIMEOUT_STYLE=countdown을 사용하여 이 두 항목을 대체할 수 있습니다.
공식 매뉴얼 원본 텍스트:
주석 문자: #으로 시작하는 문자는 주석으로 간주되므로 grub은 인라인 주석을 지원합니다.
연결 연산자: { } | & $ ; < >
예약된 키워드 및 기호: ! [[ ]] { } 메뉴 항목에서 다음까지 시간을 선택하면 elif else esac fi가 실행됩니다. 모든 키워드가 유용한 것은 아니며 향후 기능 확장을 위해 사전에 제공되는 키워드일 뿐입니다.
따옴표 및 이스케이프 문자
특수 문자는 이스케이프되어야 합니다. 이스케이프 방법에는 백슬래시 사용, 작은따옴표 사용, 큰따옴표 사용의 세 가지 방법이 있습니다.
백슬래시 이스케이프 방법은 쉘과 동일합니다.
작은 따옴표 안의 모든 문자열은 리터럴이며 특별한 의미가 없습니다. 작은 따옴표 안의 이스케이프 문자도 순수 문자로 간주됩니다. 따라서 '''는 작은따옴표를 유지할 수 없습니다. 작은 따옴표는 큰 따옴표를 사용하여 전달해야 하므로 "'"를 써야 합니다.
큰따옴표는 작은따옴표와 동일한 효과를 갖지만 "$" 및 ""를 포함한 특정 특수 문자를 이스케이프할 수 없습니다. 큰따옴표 안의 "$" 기호는 항상 원래 의미를 유지합니다. ""의 경우 백슬래시 뒤의 문자만 '$', '"', ''입니다. 또한, 라인이 백슬래시로 끝나면 라인 연속을 의미하지만 공식적으로 권장하지는 않습니다. 라인 연속을 사용하십시오.
변수 확장
$ 기호를 사용하여 변수를 참조하고 ${var}를 사용하여 var 변수를 참조할 수도 있습니다. 예를 들어 $1은 다음을 참조합니다.
첫 번째 매개변수는 마지막 명령의 종료 상태 코드를 나타내는 $?와 같은 특수 변수도 지원합니다. 위치 변수를 사용하는 경우 $*, $@ 및 $#도 지원되며 $로 표시되는 모든 매개변수가 있습니다. @도 지원되며, 각 매개변수는 분할되지 않으며, $@도 모든 변수를 나타내지만 $@의 각 매개변수는 나누어질 수 있으며, $#은 매개변수 개수를 나타냅니다.
명령 앞에 "!"가 사용되면 논리적 반전을 의미합니다. done
该命令定义了一个名为title的grub菜单项。当开机时选中该菜单项时,grub会将chosen环境变量的值赋给"--id"(如果给定了"--id"的话),执行大括号中的命令列表,如果直到最后一个命令都全部执行成功,且成功加载了对应的内核后,将执行boot命令。随后grub就将控制权交给了操作系统内核。
--class:该选项用于将菜单分组,从而使得grub可以通过主题样式为不同组的菜单显示不同的样式风格。一个menuentry中,可以使用多次class表示将该菜单分到多个组中去。
--users:该选项限定只有此处列出的用户才能访问该菜单项,不指定该选项时将表示所有用户都能访问该菜单。
--unrestricted:该选项表示所有用户都有权访问该菜单项。
--hotkey:该选项为该菜单项关联一个热键,也就是快捷键,关联热键后只要按下该键就会选中该菜单。热键只能是字母键、backspace键、tab键或del键。
--id:该选项为该菜单关联一个唯一的数值。id的值可以由ASCII字母、数字//下划线组成,且不得以数字开头。
所有其他的参数包括title都被当作位置参数传递给大括号中的命令,但title总是$1,除title外的其余参数,位置值从前向后类推。
break [n]:强制退出for/while/until循环
continue [n]:跳到下一次迭代,即进入下一次循环
return [n]:指定返回状态码
setparams [arg] …:从$1开始替换位置参数
shift [n]:踢掉前n个参数,使得第n+1个参数变为$1,但和shell中不一样的是,踢掉了前n个参数后,从$#-n+1到$#这些参数的位置不变
具体如何编写grub.cfg文件,继续看下文的命令和变量。
官方手册原文:
grub2支持很多命令,有些命令只能在交互式命令行下使用,有些命令可用在配置文件中。在救援模式下,只有insmod、ls、set和unset命令可用。
无需掌握所有的命令,掌握用的上的几个命令即可。
help [pattern]
显示能匹配到pattern的所有命令的说明信息和usage信息,如果不指定patttern,将显示所有命令的简短信息。
例如"help cmos"。
用于启动已加载的操作系统。
只在交互式命令行下可用。其实在menuentry命令的结尾就隐含了boot命令。
set [envvar=value] unset envvar
前者设置环境变量envvar的值,如果不给定参数,则列出当前环境变量。
后者释放环境变量envvar。
分别用于列出已加载的模块和调用指定的模块。
注意,若要导入支持ext文件系统的模块时,只需导入ext2.mod即可,实际上也没有ext3和ext4对应的模块。
linux file [kernel_args] linux16 file [kernel_args]
都表示装载指定的内核文件,并传递内核启动参数。linux16表示以传统的16位启动协议启动内核,linux表示以32位启动协议启动内核,但linux命令比linux16有一些限制。但绝大多数时候,它们是可以通用的。
在linux或linux16命令之后,必须紧跟着使用init或init16命令装载init ramdisk文件。
一般为/boot分区下的vmlinuz-RELEASE_NUM文件。
但在grub环境下,boot分区被当作root分区,即根分区,假如boot分区为第一块磁盘的第一个分区,则应该写成:
linux (hd0,msdos1)/vmlinuz-XXX
或者相对路径的:
set root='hd0,msdos1'
linux /vmlinuz-XXX
在grub阶段可以传递内核的启动参数(内核的参数包括3类:编译内核时参数,启动时参数和运行时参数),可以传递的启动参数非常非常多,完整的启动参数列表见:。这里只列出几个常用的:
init= :指定Linux启动的第一个进程init的替代程序。 root= :指定根文件系统所在分区,在grub中,该选项必须给定。 ro,rw :启动时,根分区以只读还是可读写方式挂载。不指定时默认为ro。 initrd :指定init ramdisk的路径。在grub中因为使用了initrd或initrd16命令,所以不需要指定该启动参数。 rhgb :以图形界面方式启动系统。 quiet :以文本方式启动系统,且禁止输出大多数的log message。 net.ifnames=0:用于CentOS 7,禁止网络设备使用一致性命名方式。 biosdevname=0:用于CentOS 7,也是禁止网络设备采用一致性命名方式。 :只有net.ifnames和biosdevname同时设置为0时,才能完全禁止一致性命名,得到eth0-N的设备名。
例如:
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=edb1bf15-9590-4195-aa11-6dac45c7f6f3 ro rhgb quiet LANG=en_US.UTF-8
另外,root启动参数有多种定义方式,可以使用UUID的方式指定,也可以直接指定根文件系统所在分区,如"root=/dev/sda2",
initrd file
只能紧跟在linux或linux16命令之后使用,用于为即将启动的内核传递init ramdisk路径。
同样,基于根分区,可以使用绝对路径,也可以使用相对路径。路径的表示方法和linux或linux16命令相同。例如:
linux16 /vmlinuz-0-rescue-d13bce5e247540a5b5886f2bf8aabb35 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro crashkernel=auto quiet
initrd16 /initramfs-0-rescue-d13bce5e247540a5b5886f2bf8aabb35.img
search [--file|--label|--fs-uuid] [--set [var]] [--no-floppy] [--hint args] name
파일 [--file], 볼륨 레이블 [--label] 및 파일 시스템 UUID [--fs-uuid]로 장치를 검색합니다.
"--set" 옵션을 사용하면 처음 발견된 장치가 환경 변수 "var"의 값으로 설정됩니다. 기본 변수 "var"는 'root'입니다.
플로피 디스크는 매우 느리고 제거되었기 때문에 검색 시 "--no-floppy" 옵션을 사용하여 플로피 디스크 검색을 비활성화할 수 있습니다.
때때로 "--hint=XXX"도 지정되는데, 이는 프롬프트 조건을 충족하는 장치가 먼저 선택된다는 의미입니다. 여러 힌트 조건이 지정되면 첫 번째 힌트가 먼저 일치되고 그 다음 두 번째 힌트가 일치됩니다. 에.
예:
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi = hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1' 367d6a77-033b-4037-bbcb-416705ead095
else
검색 --no-floppy --fs-uuid --set = 루트 367d6a77-033b-4037-bbcb-416705ead095
fi
linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro 충돌 커널=자동 자동 LANG=en_US .UTF-8
initrd16 /initramfs-3.10.0-327.el7.x86_64.img
위 if 문의 첫 번째 검색은 uuid가 "367d6a77-033b-4037-bbcb-416705ead095"인 장치를 검색합니다. 그러나 여러 힌트 옵션이 사용됩니다. 즉, bios 플랫폼에서 /boot 파티션이 (hd0, msdos1)인 장치를 먼저 일치시킨 다음 여러 힌트를 지정합니다. 그러나 검색에서는 uuid 검색 방법을 사용하기 때문에 이러한 것들은 다음과 같습니다. 예, 단일 디스크에 있는 파티션의 uuid가 고유하기 때문에 힌트 옵션은 중복됩니다.
또 다른 예로, 부팅 장치에 두 개의 부팅 파티션이 있는 경우(예: 여러 시스템이 공존하는 경우) 이는 (hd0, msdos1) 및 (hd0, msdos5)입니다. 이때 uuid 검색을 사용하지 않으면 그러나 레이블 모드 검색을 사용하십시오:
search --no-floppy --fs-label=boot --set=root --hint=hd0,msdos5
그러면 부팅 파티션(hd0,msdos5)이 선택됩니다. 이번에는 힌트를 사용하지 않으면 부팅 파티션(hd0, msdos1)이 선택됩니다.
은 true 또는 false 부울 값을 직접 반환합니다.
"표현식"의 결과가 true인지 계산합니다. true이면 0을 반환하고, 그렇지 않으면 0이 아닌 값을 반환합니다. 주로 if, while 또는 Until에 사용됩니다. 구조.
string1 == string2 | string1은 string2 |
string1 != string2 | string1과 string2는 동일하지 않습니다 |
string1 < string2 | string1은 string2 |
string1 <= string2 | 보다 알파벳순으로 작습니다. string1은 알파벳순입니다. 작거나 같음 string2 |
string1 > string2 string1은 알파벳순으로 string2보다 크거나 같습니다 | |
integer1은 정수2와 같습니다 | ㅋㅋㅋ 정수1은 정수2 |
보다 큽니다. integer1 -le 정수2 | integer1은 정수2보다 작거나 같습니다. |
integer1 -lt 정수2 | integer1 정수2 |
보다 작습니다. integer1 -ne 정수2 | integer1은 정수2 |
prefixinteger1 -pgt prefixinteger2 | eliminate non 숫자 문자열의 접두사 부분, 정수1이 다음보다 큽니다. 정수2 |
prefixinteger1 -plt prefixinteger2 | 숫자가 아닌 문자열의 접두사 부분을 제거하면 정수1이 정수2보다 작습니다 |
file1 -nt file2 | file1의 수정 시간이 file2보다 최신입니다 |
file1 -ot file2 | file1의 수정 시간이 file2 |
-d file | 보다 오래되었습니다. 파일이 존재하며 디렉터리입니다 |
-e 파일 | 파일이 존재함 |
-f 파일 | 파일이 존재하며 디렉터리가 아닙니다 |
-s file | file이 존재하고 파일이 차지하는 공간이 0보다 큽니다 |
-n string | 문자열의 길이가 0보다 큽니다 |
string | 문자열의 길이는 0보다 큽니다. 이는 -n 문자열의 길이 |
-z string | 은 0과 같습니다 |
( 표현식 ) | 전체적인 표현 |
! expression1 -o 표현식2 | 또는 (또는) |
1.4.10 cat命令读取文件内容,借此可以帮助判断哪个是boot分区,哪个是根分区。 交互式命令行下使用。 1.4.11 clear命令清屏。 1.4.12 configfile命令立即装载一个指定的文件作为grub的配置文件。但注意,导入的文件中的环境变量不在当前生效。 在grub.cfg丢失时,该命令将排上用场。 1.4.13 echo命令echo [-n] [-e] string 로그인 후 복사 "-n"和"-e"用法同shell中echo。如果要引用变量,使用${var}的方式。 1.4.14 export命令导出环境变量,若在configfile的file中导出环境变量,将会在当前环境也生效。 1.4.15 halt和reboot命令关机或重启 1.4.16 ls命令ls [args] 로그인 후 복사 如果不给定任何参数,则列出grub可见的设备。 如果给定的参数是一个分区,则显示该分区的文件系统信息。 如果给定的参数是一个绝对路径表示的目录,则显示该目录下的所有文件。 例如: 1.4.17 probe命令probe [--set var] --partmap|--fs|--fs-uuid|--label device 로그인 후 복사 探测分区或磁盘的属性信息。如果未指定--set,则显示指定设备对应的信息。如果指定了--set,则将对应信息的值赋给变量var。 --partmap:显示是gpt还是mbr格式的磁盘。 --fs:显示分区的文件系统。 --fs-uuid:显示分区的uuid值。 --label:显示分区的label值。 1.4.18 save_env和list_env命令将环境变量保存到环境变量块中,以及列出当前的环境变量块中的变量。 1.4.19 loopback命令loopback [-d] device file 로그인 후 복사 将file映射为回环设备。使用-d选项则是删除映射。 例如: loopback loop0 /path/to/imagels (loop0)/ 로그인 후 복사 1.4.20 normal和normal_exit命令进入和退出normal模式,normal是相对于救援模式而言的,只要不是在救援模式下,就是在normal模式下。 救援模式下,只能使用非常少的命令,而normal模式下则可以使用非常多的命令。 1.4.21 password和password_pbkdf2命令password user clear-password password_pbkdf2 user hashed-password 로그인 후 복사 前者使用明文密码定义一个名为user的用户。不建议使用此命令。 后者使用哈希加密后的密码定义一个名为user的用户,加密的密码通过"grub-mkpasswd-pbkdf2"工具生成。建议使用该命令。 1.5 几个常设置的内置变量1.5.1 chosen变量当开机时选中某个菜单项启动时,该菜单的title将被赋值给chosen变量。该变量一般只用于引用,而不用于修改。 1.5.2 cmdpath变量grub2加载的core.img的目录路径,是绝对路径,即包括了设备名的路径,如(hd0,gpt1)/boot/grub2/。该变量值不应该修改。 1.5.3 default变量指定默认的菜单项,一般其后都会跟随timeout变量。 default指定默认菜单时,可使用菜单的title,也可以使用菜单的id,或者数值顺序,当使用数值顺序指定default时,从0开始计算。 1.5.4 timeout变量设置菜单等待超时时间,设置为0时将直接启动默认菜单项而不显示菜单,设置为"-1"时将永久等待手动选择。 1.5.5 fallback变量当默认菜单项启动失败,则使用该变量指定的菜单项启动,指定方式同default,可使用数值(从0开始计算)、title或id指定。 1.5.6 grub_platform变量指定该平台是"pc"还是"efi",pc表示的就是传统的bios平台。 该变量不应该被修改,而应该被引用,例如用于if判断语句中。 1.5.7 prefix变量在grub启动的时候,grub自动将/boot/grub2目录的绝对路径赋值给该变量,使得以后可以直接从该变量所代表的目录下加载各文件或模块。 例如,可能自动设置为:
所以可以使用"$prefix/grubN.cfg"来引用/boot/grub2/grubN.cfg文件。 该变量不应该修改,且若手动设置,则必须设置正确,否则牵一发而动全身。 1.5.8 root变量该变量指定根设备的名称,使得后续使用从"/"开始的相对路径引用文件时将从该root变量指定的路径开始。一般该变量是grub启动的时候由grub根据prefix变量设置而来的。 例如prefix=(hd0,gpt1)/boot/grub2,则root=(hd0,gpt1),后续就可以使用相对路径/vmlinuz-XXX表示(hd0,gpt1)/vmlinuz-XXX文件。 注意:在Linux中,从根"/"开始的路径表示绝对路径,如/etc/fstab。但grub中,从"/"开始的表示相对路径,其相对的基准是root变量设置的值,而使用"(dev_name)/"开始的路径才表示绝对路径。 一般root变量都表示/boot所在的分区,但这不是绝对的,如果设置为根文件系统所在分区,如root=(hd0,gpt2),则后续可以使用/etc/fstab来引用"(hd0,gpt2)/etc/fstab"文件。 该变量在grub2中一般不用修改,但若修改则必须指定正确。 另外,root变量还应该于linux或linux16命令所指定的内核启动参数"root="区分开来,内核启动参数中的"root="的意义是固定的,其指定的是根文件系统所在分区。例如:
一般情况下,/boot都会单独分区,所以root变量指定的根设备和root启动参数所指定的根分区不是同一个分区,除非/boot不是单独的分区,而是在根分区下的一个目录。 1.6 grub配置和安装示例首先写一个grub.cfg。例如此处,在msdos磁盘上安装了两个操作系统,CentOS 7和CentOS 6。 # 设置一些全局环境变量 set default=0set fallback=1set timeout=3# 将可能使用到的模块一次性装载完 # 支持msdos的模块insmod part_msdos # 支持各种文件系统的模块insmod exfatinsmod ext2insmod xfsinsmod fatinsmod iso9660 # 定义菜单 menuentry 'CentOS 7' --unrestricted { search --no-floppy --fs-uuid --set=root 367d6a77-033b-4037-bbcb-416705ead095 linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=b2a70faf-aea4-4d8e-8be8-c7109ac9c8b8 ro biosdevname=0 net.ifnames=0 quiet initrd16 /initramfs-3.10.0-327.el7.x86_64.img } menuentry 'CentOS 6' --unrestricted { search --no-floppy --fs-uuid --set=root f5d8939c-4a04-4f47-a1bc-1b8cbabc4d32 linux16 /vmlinuz-2.6.32-504.el6.x86_64 root=UUID=edb1bf15-9590-4195-aa11-6dac45c7f6f3 ro quiet initrd16 /initramfs-2.6.32-504.el6.x86_64.img } 로그인 후 복사 然后执行grub安装操作。 shell> grub2-install /dev/sda 로그인 후 복사 로그인 후 복사 1.7 传统grub简述因为本文主要介绍grub2,所以传统的grub只简单介绍下,其实前面已经提及了很多传统grub和grub2的比较了。另外,传统grub已足够强大,足够应付一般的需求。 1.7.1 grub安装例如安装到/dev/sda上。 shell> grub-install /dev/sda 로그인 후 복사 1.7.2 grub.conf配置default=0 # 默认启动第一个系统 timeout=5 # 等待超时时间5秒 splashimage=(hd0,0)/grub/splash.xpm.gz # 背景图片 hiddenmenu # 隐藏菜单,若要显式,在启动时按下ESC title Red Hat Enterprise Linux AS (2.6.18-92.el5) # 定义操作系统的说明信息 root (hd0,0) kernel /vmlinuz-2.6.18-92.el5 ro root=/dev/sda2 rhgb quiet initrd /initrd-2.6.18-92.el5.img 로그인 후 복사 구성 방법을 설명하기 전에 부팅이 후속 경로 구성에 영향을 미치는 독립 파티션인지 여부라는 핵심 사항을 설명해야 합니다. 일반 운영 체제에서 /boot/grub/grub.conf 파일을 확인하면 NOTICE 섹션에서 독립적인 부팅 파티션이 있는지 묻는 메시지를 볼 수 있습니다. 있는 경우 커널 및 initrd의 경로가 /boot 대신 /에서 시작한다는 의미입니다(예: /vmlinuz-xxx). 독립된 부팅 파티션이 없으면 커널 및 initrd의 경로에 부팅 경로를 지정해야 합니다. 예를 들어, 부팅에는 파티션이 / 파일 시스템 아래의 디렉터리이고 /boot/vmlinuz-xxx가 없습니다. root(hd0,0)은 grub이 인식하는 루트를 정의합니다. 일반적으로 boot가 위치한 파티션이 정의되어 있는데, grub은 hd만 인식할 수 있으므로 여기서는 hd만 사용할 수 있습니다. hd0,0의 두 번째 0은 boot가 첫 번째 파티션에 있다는 의미입니다. . grub2 파티션 계산은 1부터 시작하는데, 이는 기존 grub과 grub2의 차이입니다. kernel은 grub2 linux 명령 또는 linux16 명령과 동일한 커널 파일의 경로 및 시작 매개변수를 정의합니다. 먼저 매개변수를 설명합니다. ro는 읽기 전용을 의미합니다. root=/dev/sda[N] 또는 root=UUID="device_uuid_num"은 루트 파일 시스템이 위치한 파티션을 지정합니다. rhgb는 운영 체제 시작 프로세스 중에 일부 정보를 출력하기 위해 그래픽 인터페이스를 사용한다는 의미입니다. 이를 생략하면 시작 속도가 빨라질 수 있으며 운영 체제를 시작할 때 정보를 자동으로 출력한다는 의미입니다. 경로를 다시 설명하자면, 부팅이 독립 파티션인 경우 커널 경로는 /vmlinuz-xxx로 정의되며, 독립 파티션이 없는 경우에는 일반적으로 루트 파일 시스템 아래의 디렉터리이므로 이를 지정합니다. 일반적으로 /boot/vmlinuz-xxx입니다. initrd는 init ramdisk의 경로를 정의합니다. 경로는 커널과 동일한 방식으로 정의됩니다. 경로 외에는 매개변수가 없습니다. 또는 아래와 같이 UUID 방식을 사용합니다. root= 옵션을 지정하지 않으면 "루트가 없거나 비어 있습니다...dracut...커널 패닉" 오류가 보고됩니다. 아래 그림과 같습니다.
위 내용은 grub2에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요! 본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
최신 이슈
자식 창이 부모 창을 작동하지만 출력이 응답하지 않습니다.
처음 두 문장은 실행 가능하지만 마지막 문장은 구현할 수 없습니다.
에서 2024-04-19 15:37:47
0
1
1698
상위 창에 출력이 없습니다.
document.onclick = function(){ window.opener.document.write('나는 자식 창의 출력입니다.');
에서 2024-04-18 23:52:34
0
1
1601
관련 주제
더>
|