[관련 게시물]
멀티부팅 시스템을 구축하는 과정에서 손상된 GRUB을 boot-repair라는 패키지를 이용해 간편하게 복구하는 방법을 알아본 적이 있습니다.
그러나 이 방법을 쓰는데는 상당한 제약이 있습니다. boot-repair 패키지는 데비안 계열(Debian, Ubuntu, Linux Mint 등) 패키지(.Deb)이기 때문에 레드햇 등 다른 계열 리눅스에서는 사용하기 힘듭니다. 또한 boot-repair 패키지는 GUI 기반이기 때문에 데스크톱 환경이 없는 서버에서는 사용할 수 없습니다.
이럴 때를 대비해 리눅스 시동 디스크만으로 터미널 환경 즉 명령줄(CLI) 환경에서 복구할 수 있는 방법을 알아 둘 필요가 있습니다.
그런데 각 리눅스 계열마다 복구 방법이 다소 상이합니다. 레드햇 계열이라면 시동 디스크 부팅화면에서 아래 단계에 들어가 복구 작업을 진행해주면 됩니다.
CentOS 8의 예
Troubleshooting → Rescue a CentOS Linux system
레드햇 계열 등 다른 계열 리눅스의 보다 자세한 GRUB 복구 방법은 다른 유능한 분들의 글들을 참고하시기 바랍니다.
CLI를 통한 부트로더(boot loader) GNU GRUB 복구 과정
GRUB 손상 전 환경
OS : Ubuntu 20.04
GRUB 버전 : GNU GRUB 2.04
GRUB 손상 이유 : 멀티 부팅 시스템을 위해 Windows 10 설치
GRUB 복구 작업을 하게 되는 이유는 여러 이유가 존재할 수 있지만 이 글에서는 위 상자에서 적은 상황을 상정하고 복구하는 방법을 진행하도록 하겠습니다.
우분투 시동 디스크로 부팅
2019/08/24 - [리눅스/Ubuntu] - 우분투 시동 디스크 만들기
2020/04/24 - [리눅스/공통] - Rufus로 부팅 가능한 USB 디스크 만들기 - 예시 : 우분투(Ubuntu) 20.04
우분투 시동디스크로 부팅 후 Try Ubuntu를 선택합니다.
부팅 후 터미널을 실행합니다. 단축키는 Crl+Alt+T입니다.
파티션 이름 및 구조 파악
$ sudo fdisk -l
fdisk는 파티션을 관리하는 기본 명령입니다. -l 옵션을 사용하여 현재 시스템에 물려 있는(마운트 여부와는 상관 없이) 디스크 및 파티션의 자세한 정보를 확인할 수 있습니다.
ubuntu@ubuntu:~$ sudo fdisk -l Disk /dev/loop0: 1.98 GiB, 2103640064 bytes, 4108672 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes - 중략 - Disk /dev/sda: 1.102 TiB, 2199022206976 bytes, 4294965248 sectors Disk model: VBOX HARDDISK Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자 Device Start End Sectors Size Type /dev/sda1 2048 1050623 1048576 512M EFI System /dev/sda2 1050624 2098202623 2097152000 1000G Linux filesystem /dev/sda3 2098202624 2098235391 32768 16M Microsoft reserved /dev/sda4 2098235392 4294963199 2196727808 1T Microsoft basic data Disk /dev/sdb: 29.12 GiB, 31260704768 bytes, 61056064 sectors Disk model: Cruzer Switch Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x8자리 영숫자 Device Boot Start End Sectors Size Id Type /dev/sdb1 * 0 5439487 5439488 2.6G 0 Empty /dev/sdb2 5017392 5025327 7936 3.9M ef EFI (FAT-12/16/32) /dev/sdb3 5439488 61056063 55616576 26.5G 83 Linux ubuntu@ubuntu:~$
위 터미널 내용을 보면 총 아래와 같이 세 유형의 디스크를 확인할 수 있습니다.
Disk /dev/loopN / Disk /dev/sdaN / Disk /dev/sdbN
Disk /dev/loopN은 루프 디바이스(loop device)로, 블록 디바이스에 접근할 수 있는 일반 파일을 만들어주는 일종의 가상 디바이스입니다.
보다 자세한 내용은 위 링크를 참고하시기 바랍니다.
디스크 /dev/sda는 1차 대용량 기억장치를 의미하는 것으로 일반적으로 OS가 설치되어 있는 디스크를 의미합니다.
디스크 /dev/sdb는 2차 대용량 기억장치를 의미하는 것으로 일반적으로 OS가 설치되어 있지 않는 디스크를 의미하며 시스템 내장 하드 디스크가 하나뿐인 경우 USB 메모리 저장장치 등 이동식 저장 매체를 의미합니다.
즉 /dev/sdX는 시스템에서 이용할 수 있는 물리적 저장장치를 의미합니다.
근래에는 장치명으로 /dev/sdX를 사용하는데 이 장치명은 입출력 버스 인터페이스로 SCSI 방식을 사용하는 저장장치를 의미합니다. 이전에는 입출력 버스 인터페이스로 IDE, 또는 E-IDE 방식을 사용했던 적이 있습니다. 이러한 저장장치에 대한 장치명으로는 /dev/hdX를 사용했었으나 이제는 보다 진보된 SCSI 방식을 채택한 저장장치를 사용하게되면서 장치명 /dev/hdX은 리눅스를 다루는 오래된 웹문서에서나 찾아 볼 수 있게 되었습니다.
그외 리눅스에서 사용되는 각종 장치명에 대한 개략적 설명은 위 링크르 참고하시기 바랍니다.
sudo fdisk -l 명령을 입력해 출력되는 정보들 중 우리가 확인할 것은 EFI System과 Linux filesystem의 장치명을 확인하는 것입니다.
위에서 확인해보니 각 파티션의 장치명은 다음과 같습니다.
EFI System : /dev/sda1
Linux filesystem : /dev/sda2
이렇게 확인한 장치명을 기억해두도록 합시다.
근래는 대부분의 시스템들이 EFI System을 사용하기 때문에 EFI System 장치명도 확인되겠지만 드물게 MBR 을 사용하는 구형 시스템인 경우 EFI System 파티션이 구성되지 않기 때문에 관련 장치명도 존재하지 않습니다.
$ sudo blkid
blkid 명령어는 파일시스템의 유형 등을 확인할 때 씁니다.
ubuntu@ubuntu:~$ sudo blkid /dev/sda1: UUID="4자리 영숫자-4자리 영숫자" TYPE="vfat" PARTLABEL="EFI System Partition" PARTUUID="8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자" /dev/sda2: UUID="8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자" TYPE="ext4" PARTUUID="8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자" /dev/sda4: UUID="16자리 영숫자" TYPE="ntfs" PARTLABEL="Basic data partition" PARTUUID="8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자" /dev/sr0: UUID="2020-06-04-16-51-04-85" LABEL="VBox_GAs_6.1.10" TYPE="iso9660" /dev/sdb1: UUID="2020-07-31-16-51-12-00" LABEL="Ubuntu 20.04.1 LTS amd64" TYPE="iso9660" PTUUID="8자리 영숫자" PTTYPE="dos" PARTUUID="8자리 영숫자-2자리 숫자" /dev/loop0: TYPE="squashfs" /dev/loop1: TYPE="squashfs" /dev/loop2: TYPE="squashfs" /dev/loop3: TYPE="squashfs" /dev/loop4: TYPE="squashfs" /dev/loop5: TYPE="squashfs" /dev/sda3: PARTLABEL="Microsoft reserved partition" PARTUUID="8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자" /dev/sdb2: SEC_TYPE="msdos" UUID="4자리 영숫자-4자리 영숫자" TYPE="vfat" PARTUUID="8자리 영숫자-2자리 숫자" /dev/sdb3: LABEL="writable" UUID="8자리 영숫자-4자리 영숫자-4자리 영숫자-4자리 영숫자-12자리 영숫자" TYPE="ext4" PARTUUID="8자리 영숫자-2자리 숫자" ubuntu@ubuntu:~$
여기서 우리가 확인할 것은 EFI System 장치의 UUID입니다. 물론 여기서 확인하지 못하더라도 나중에 확인할 수 있습니다.
리눅스 주 파티션 마운트
$ sudo mount /dev/sda2 /mnt
mount는 기본적으로 특정 장치를 사용자가 지정한 디렉터리에 연결해주는 명령입니다.
ubuntu@ubuntu:~$ sudo mount /dev/sda2 /mnt ubuntu@ubuntu:~$
우분투가 설치되어 있는 주 파티션을 /mnt 디렉터리에 마운트해줍니다.
필수 디렉터리 바인드 마운트
$ for i in /sys /proc /run /dev /dev/pts; do sudo mount --bind "$i" "/mnt$i"; done
시스템 구동에 필요한 여러 필수 디렉터리들을 바인드해 마운트해줍니다.
그 이유는 이따가 /mnt 디렉터리를 가상 루트 디렉터리로 설정하여 현재 구동 중인 우분투 Live 시동 디스크가 아니라 가상 루트 디렉터리의 정보를 토대로 구동 및 작업하기 이함입니다.
위 명령을 이해하기 위해서는 Bash 셸스크립트 구조적 명령의 반복구문 for문을 이애해야 합니다. 이 내용은 리눅스 초심자에게는 꽤 까다로울 수 있습니다. 그러나 최대한 풀어서 설명해보도록 하겠ㅅㅂ니다.
for 문
위에 사용된 for 문은 Bash 셸스크립트에서 사용되는 구조적 명령 중 하나로, 특정 조건을 만족할 때까지 일련의 명령을 반복하는 일종의 반복 구문(= loop 구문)입니다.
이 for 문은 문법은 다소 차이가 날지라도 다른 셸스크립트 뿐만 아니라 파이썬 등 대부분의 프로그래밍 언어에서 사용되는 구문입니다.
for문의 기본 문법은 아래와 같습니다.
for var in list
do
command
done
위 구문을 한줄로 표현하고자 할 때 아래와 같이 작성합니다.
for var in list; do command; done
위 예시와 같이 후행하는 do 문을 세미콜론(;)으로 앞의 list 항목과 구분해주어야 합니다.
var 자리에는 변수명을, list 매개변수에는 반복에 사용할 값들을 나열해줍니다. 그리고 command 자리에는 반복 실행할 명령을 적어줍니다.
for i in /sys /proc /run /dev /dev/pts; do sudo mount --bind "$i" "/mnt$i"; done
즉 위 구문을 인간이 이해할 수 있는 언어로 번역하면 다음과 같습니다.
반복 적용할 변수를 i라 설정하고 변수 i에 적용할 값(즉 동일한 명령을 수행할 값들)들로 /sys, /proc, /run, /dev, /dev/pts 디렉터리를 지정합니다.
각 디렉터리를 /mnt 디렉터리에 바인드하여 마운트해줍니다.
즉, 현재 마운트트되어 있어 시스템 구동에 사용되고 있는 /sys, /proc, /run, /dev, /dev/pts 디렉터리들을 --bind 옵션을 추가하여 다른 디렉터리인 /mnt 디렉터리 아래에 붙여 마운트해줍니다.
EFI 시스템 장치 확인
$ sudo fdisk -l | grep -i efi
grep은 입력받은 문자열을 찾을 때 쓰는 명령으로, 위 예시에서 사용된 -i 옵션은 대소문자를 무시할 때 씁니다.
ubuntu@ubuntu:~$ sudo fdisk -l | grep -i efi /dev/sda1 2048 1050623 1048576 512M EFI System /dev/sdb2 5017392 5025327 7936 3.9M ef EFI (FAT-12/16/32) ubuntu@ubuntu:~$
위 명령을 이용해 EFI System의 장치명을 확인해줍니다.
/dev/sda1는 기존 시스템의 EFI System 장치명입니다. /dev/sdb2는 우분투 시동디스크 USB 메모리 저장장치에 존재하는 EFI System 장치명입니다.
우리는 기존 시스템의 손상된 GRUB을 복구하고자 하는 것이므로 기존 시스템의 EFI System 장치인 /dev/sda1도 마운트해주도록 합시다.
EFI 시스템 장치 마운트
$ sudo mount /dev/sda1 /mnt/boot/efi
기존 시스템의 EFI System 장치인 /dev/sda1을 mnt/boot/efi에 마운트해줍시다.
이때 mount할 때 --bind를 사용하지 않는 이유는 마운트하고자 하는 것이 디렉터리가 아닌 장치이기 때문입니다.
mount(8)
Description
- 중략 -
The mount command serves to attach the filesystem found on some device to the big file tree.
- 중략-
The standard form of the mount command, is
mount -t type device dir
기본적으로 mount는 디스크 드라이브 같은 블록 디바이스(Block Device)만 마운트가 가능합니다. 하지만 장치가 아닌 디렉터리를 다른 디렉터리에 마운트할 수도 있는데 이땐 --bind 옵션을 사용해야 합니다.
The bind mounts.
Since Linux 2.4.0 it is possible to remount part of the file hierarchy somewhere else. The call is
mount --bind olddir newdir
or shortoption
mount -B olddir newdir
or fstab entry is:
/olddir /newdir none bind
가상 루트 디렉터리 지정
$ sudo chroot /mnt
chroot는 가상의 루트 디렉터리를 생성할 때 사용합니다. exit 명령으로 빠져나가기 전까지 chroot 명령 이후의 자식 프로세스로 이루어지는 모든 작업은 해당 가상 루트 디렉터리를 기반으로 이루어집니다.
보다 자세한 내용은 위 링크를 참고하시기 바랍니다.
ubuntu@ubuntu:~$ sudo chroot /mnt root@ubuntu:/#
사용자가 root로 전환됩니다.
GRUB 업데이트
# update-grub
update-grub은 grub의 업데이트 명령입니다.
만약 오류가 발생한다면 GRUB을 인스톨해주어야 합니다.
GRUB 인스톨
# grub-install /dev/sda
grub-install은 grub 설치 명령으로 grub을 설치할 장치를 인수로 가집니다.
root@ubuntu:/# grub-install /dev/sda Installing for x86_64-efi platform. Installation finished. No error reported. root@ubuntu:/#
이제 본격적으로 GRUB을 복구합니다. 이 명령은 GRUB을 설치합니다.
GRUB 업데이트
# update-grub
update-grub은 grub의 업데이트 명령입니다.
root@ubuntu:/# update-grub Sourcing file `/etc/default/grub' Sourcing file `/etc/default/grub.d/init-select.cfg' Generating grub configuration file ... Found linux image: /boot/vmlinuz-5.4.0-54-generic Found initrd image: /boot/initrd.img-5.4.0-54-generic Found linux image: /boot/vmlinuz-5.4.0-42-generic Found initrd image: /boot/initrd.img-5.4.0-42-generic Found linux image: /boot/vmlinuz-5.4.0-39-generic Found initrd image: /boot/initrd.img-5.4.0-39-generic grub-probe: error: cannot find a GRUB drive for /dev/sdb1. Check your device.map. Found Windows Boot Manager on /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi Adding boot menu entry for UEFI Firmware Settings done root@ubuntu:/#
EFI 시스템 장치 UUID 동일성 체크
# blkid | grep -i efi
root@ubuntu:/# blkid | grep -i efi /dev/sda1: UUID="D827-9E9F" TYPE="vfat" PARTLABEL="EFI System Partition" PARTUUID="7e1a1d1f-3744-47e3-a714-2a60c7523b97" root@ubuntu:/#
기존 시스템의 EFI System 장치의 UUID를 확인합니다.
# grep -i efi /etc/fstab
root@ubuntu:/# grep -i efi /etc/fstab # /boot/efi was on /dev/sda1 during installation UUID=D827-9E9F /boot/efi vfat umask=0077 0 1 root@ubuntu:/#
이제 chroot 명령이 실행된 상태(/mnt 디렉터리를 루트 디렉터리로 설정한 이후)에서 fstab 파일 내의 /boot/efi의 UUID를 화신합니다.
기존 시스템의 EFI System 장치(예 : /dev/sda1)의 UUID와 /etc/fstab 파일 내의 /boot/efi의 UUID가 동일해야 합니다.
보통 동일하겠지만 GRUB 또는 시스템의 손상 유형에 따라 UUID가 다를 수도 있습니다.
blkid 명령으로 확인한 현재 EFI 파티션 UUID가 /etc/fstab의 파티션 UUID와 다른 경우 /etc/fstab의 EFI의 UUID 정보를 현재 UUID로 수정해줍니다.
가상 루트 디렉터리 지정 해제
# exit
root@ubuntu:/# exit exit ubuntu@ubuntu:~$
가상 루트 디렉터리 설정(chroot)를 해제해줍니다.
루트 디렉터리가 chroot 명령 수행하기 전으로 복구되고 사용자 역시 ubuntu로 전환됩니다.
시스템 재부팅
$ sudo reboot
GNU GRUB의 복구 작업은 마무리되었습니다.
이제 시스템을 재부팅하고 시동디스크를 제거한 다음 기존 시스템으로 부팅 절차를 진행해줍니다.
그럼 위 그림과 같이 GNU GRUB이 정상적으로 복구된 것을 확인할 수 있습니다.
'리눅스 > Debian or Ubuntu' 카테고리의 다른 글
우분투 리눅스 커널 관리 01 - 오래된 커널 제거 (0) | 2021.03.08 |
---|---|
Ubuntu 20.04에서 엡손 프린터/스캐너/복합기 리눅스 드라이버 설치 방법 2 - 드라이버 및 유틸리티 설치 (0) | 2021.02.12 |
Ubuntu 20.04에서 엡손 프린터/스캐너/복합기 리눅스 드라이버 설치 방법 1 - 드라이버 및 유틸리티 다운로드 (0) | 2021.02.10 |
주요 프린터/스캐너/복합기 제조사별 드라이버 다운로드 페이지 (0) | 2021.02.08 |
Linux(Ubuntu) - Windows 10 멀티부팅(듀얼부팅) 시스템 구축 (0) | 2020.12.03 |
이미지로 보는 우분투 20.10 설치 (0) | 2020.11.08 |
우분투(Ubuntu) 20.10 Groovy Gorilla의 주요 특징과 설치 및 업그레이드 (0) | 2020.11.06 |
우분투 관련 기존 포스팅 중 우분투 20.04에 맞춰 업데이트한 글 목록 - 업데이트 중 (0) | 2020.07.08 |