· 7 years ago · Oct 02, 2018, 09:20 PM
1#!/bin/bash
2VERSION='0.77';
3RELEASE_DATE='10 June 2018';
4LAST_GIT_COMMIT_SHORTLOG='';
5LAST_GIT_COMMIT_DATE='';
6################################################################################
7# #
8# Copyright (c) 2009-2010 Ulrich Meierfrankenfeld #
9# Copyright (c) 2011-2012 Gert Hulselmans #
10# Copyright (c) 2013-2018 Andrei Borzenkov #
11# #
12# Permission is hereby granted, free of charge, to any person obtaining a copy #
13# of this software and associated documentation files (the "Software"), to #
14# deal in the Software without restriction, including without limitation the #
15# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or #
16# sell copies of the Software, and to permit persons to whom the Software is #
17# furnished to do so, subject to the following conditions: #
18# #
19# The above copyright notice and this permission notice shall be included in #
20# all copies or substantial portions of the Software. #
21# #
22# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
23# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
24# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
25# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
26# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING #
27# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS #
28# IN THE SOFTWARE. #
29# #
30################################################################################
31# #
32# Current developer: Andrei Borzenkov #
33# #
34# Past developer: Gert Hulselmans #
35# Past developer: Ulrich Meierfrankenfeld (meierfra) (ubuntuforums.org) #
36# Past contributor: caljohnsmith (ubuntuforums.org) #
37# #
38# Hosted at: https://github.com/arvidjaar/bootinfoscript #
39# Forked from: http://sourceforge.net/projects/bootinfoscript/ #
40# #
41# The birth of Boot Info Script: #
42# http://ubuntuforums.org/showthread.php?t=837791 #
43# #
44# Tab width: 8 spaces #
45# #
46################################################################################
47
48
49
50## Check if the script is run with bash as shell interpreter.
51
52if [ -z "$BASH_VERSION" ] ; then
53 echo 'Boot Info Script needs to be run with bash as shell interpreter.' >&2;
54 exit 1;
55fi
56
57
58
59## Display help text ##
60#
61# ./bootinfoscript -h
62# ./bootinfoscript -help
63# ./bootinfoscript --help
64
65help () {
66 cat <<- HELP
67
68 Usage Boot Info Script:
69 -----------------------
70
71 Run the script as sudoer:
72
73 sudo ${0} <outputfile>
74
75 or if your operating system does not use sudo:
76
77 su -
78 ${0} <outputfile>
79
80
81 When running the script, without specifying an output file, all the output
82 is written to the file "RESULTS.txt" in the same folder as the script.
83
84 But when run from /bin, /sbin, /usr/bin, or another system folder, the file
85 "RESULTS.txt" is written to the home directory of the user.
86
87 When the file "RESULTS.txt" already exists, the results will be written to
88 "RESULTS1.txt". If "RESULTS1.txt" exists, the results will be written to
89 "RESULTS2.txt", ...
90
91
92 To get version number, release date, last git commit and git retrieval date
93 of this script, use (no root rights needed):
94
95 ${0} -v
96 ${0} -V
97 ${0} --version
98
99
100 To get this help text, use (no root rights needed):
101
102 ${0} -h
103 ${0} -help
104 ${0} --help
105
106
107 To automatically gzip a copy of the output file, use (root rights needed):
108
109 ${0} -g <outputfile>
110 ${0} --gzip <outputfile>
111
112
113 To write the output to stdout instead of a file, use (root rights needed):
114
115 ${0} --stdout
116
117
118 The last development version of Boot Info Script can be downloaded, with:
119 (no root rights needed)
120
121 ${0} --update <filename>
122
123 If no filename is specified, the file will be saved in the home dir as
124 "bootinfoscript_YYYY-MM-DD_hh:mm:ss".
125
126 HELP
127
128 exit 0;
129}
130
131
132
133## Download the last development version of BIS from git: ##
134#
135# ./bootinfoscript --update <filename>
136#
137# If no filename is specified, the file will be saved in the home dir as
138# "bootinfoscript_YYYY-MM-DD_hh:mm:ss".
139
140update () {
141 local git_ref_url='https://api.github.com/repos/arvidjaar/bootinfoscript/git/refs/heads/master'
142 local git_commit_url='https://api.github.com/repos/arvidjaar/bootinfoscript/git/commits'
143 local git_contents_url='https://github.com/arvidjaar/bootinfoscript/raw/master/bootinfoscript'
144
145 # Check if date is available.
146 if [ $(type date > /dev/null 2>&1 ; echo $?) -ne 0 ] ; then
147 echo '"date" could not be found.' >&2;
148 exit 1;
149 fi
150
151 # Get current UTC time in YYYY-MM-DD-hh:mm:ss format.
152 UTC_TIME=$(date --utc "+%Y-%m-%d %T");
153
154 if [ ! -z "$1" ] ; then
155 GIT_BIS_FILENAME="$1";
156 else
157 GIT_BIS_FILENAME="${HOME}/bootinfoscript_${UTC_TIME/ /_}"
158 fi
159
160 # Check if wget or curl is available
161 if [ $(type wget > /dev/null 2>&1 ; echo $?) -eq 0 ] ; then
162 printf '\nDownloading last development version of Boot Info Script from git:\n\n';
163 LAST_GIT_COMMIT_ID=$(wget -O - "${git_ref_url}" | sed -ne 's/^.*"sha": "\(.*\)".*$/\1/p');
164 LAST_GIT_COMMIT=$(wget -O - "${git_commit_url}/$LAST_GIT_COMMIT_ID");
165
166 wget -O "${GIT_BIS_FILENAME}" "${git_contents_url}";
167 elif [ $(type curl > /dev/null 2>&1 ; echo $?) -eq 0 ] ; then
168 printf 'Downloading last development version of Boot Info Script from git:\n\n';
169 LAST_GIT_COMMIT_ID=$(curl "${git_ref_url}" | sed -ne 's/^.*"sha": "\(.*\)".*$/\1/p');
170 LAST_GIT_COMMIT=$(curl "${git_commit_url}/$LAST_GIT_COMMIT_ID");
171
172 curl -o "${GIT_BIS_FILENAME}" "${git_contents_url}";
173 else
174 printf '"wget" or "curl" could not be found.\nInstall at least one of them and try again.\n' >&2;
175 exit 1;
176 fi
177
178 # First date is Author, second date is Commit
179 LAST_GIT_COMMIT_DATE=$(echo "${LAST_GIT_COMMIT}" | sed -ne 's/^[[:space:]]*"date": "\(.*\)"[[:space:]]*$/\1/p' | tail -1);
180 LAST_GIT_COMMIT_SHORTLOG=$(echo "${LAST_GIT_COMMIT}" | sed -n -e '/^[[:space:]]*"message":/ { s/^[[:space:]]*"message": "\(.*\)",[[:space:]]*$/\1/ ; s/\\n.*$// ; p }');
181
182 # Set the retrieval date in just downloaded script.
183 sed -i -e "4,0 s@LAST_GIT_COMMIT_SHORTLOG='';@LAST_GIT_COMMIT_SHORTLOG='${LAST_GIT_COMMIT_SHORTLOG}';@" \
184 -e "5,0 s/LAST_GIT_COMMIT_DATE='';/LAST_GIT_COMMIT_DATE='${LAST_GIT_COMMIT_DATE}';/" \
185 "${GIT_BIS_FILENAME}";
186
187 printf '\nThe development version of Boot Info Script is saved as:\n"%s"\n\n' "${GIT_BIS_FILENAME}";
188 exit 0;
189}
190
191
192
193## Display version, release, last git commit and git retrieval date of the script when asked: ##
194#
195# ./bootinfoscript -v
196# ./bootinfoscript -V
197# ./bootinfoscript --version
198
199version () {
200 printf '\nBoot Info Script version: %s\nRelease date: %s' "${VERSION}" "${RELEASE_DATE}";
201
202 if [ ! -z "${LAST_GIT_COMMIT_SHORTLOG}" ] ; then
203 printf '\nLast git commit: %s\nCommit date: %s' \
204 "${LAST_GIT_COMMIT_SHORTLOG}" "${LAST_GIT_COMMIT_DATE}";
205 fi
206
207 printf '\n\n';
208
209 exit 0;
210}
211
212
213
214## Gzip a copy of the output file? ##
215gzip_output=0; # off=0
216
217## Write the output to the standard output instead of to a file? ##
218stdout_output=0; # off=0
219
220
221
222## Get arguments passed to the script. ##
223
224process_args () {
225 if [ ${#@} -ge 1 ] ; then
226 # Process arguments.
227 case "$1" in
228 -g ) gzip_output=1; if [ ! -z "$2" ] ; then LogFile_cmd="$2"; fi;;
229 --gzip ) gzip_output=1; if [ ! -z "$2" ] ; then LogFile_cmd="$2"; fi;;
230 -h ) help;;
231 -help ) help;;
232 --help ) help;;
233 --stdout ) stdout_output=1;;
234 --update ) update "$2";;
235 -v ) version;;
236 -V ) version;;
237 --version ) version;;
238 -* ) help;;
239 * ) LogFile_cmd="$1";;
240 esac
241 fi
242}
243
244
245
246
247## Get arguments passed to the script. ##
248
249process_args ${@};
250
251
252
253## Display version number, release and git retrieval date. ##
254
255printf '\nBoot Info Script %s [%s]' "${VERSION}" "${RELEASE_DATE}";
256
257if [ ! -z "${LAST_GIT_COMMIT_SHORTLOG}" ] ; then
258 printf '\n Last git commit: %s\n Commit date: %s' \
259 "${LAST_GIT_COMMIT_SHORTLOG}" "${LAST_GIT_COMMIT_DATE}";
260fi
261
262printf '\n\n';
263
264
265
266## Check whether Boot Info Script is run with root rights or not. ##
267
268if [ $(type whoami > /dev/null 2>&1 ; echo $?) -ne 0 ] ; then
269 echo 'Please install "whoami" and run Boot Info Script again.' >&2;
270 exit 1;
271elif [ $(whoami) != 'root' ] ; then
272 cat <<- EOF >&2
273 Please use "sudo" or become "root" to run this script.
274
275 Run the script as sudoer:
276
277 sudo ${0} <outputfile>
278
279 or if your operating system does not use sudo:
280
281 su -
282 ${0} <outputfile>
283
284 For more info, see the help:
285
286 ${0} --help
287
288 EOF
289 exit 1;
290fi
291
292
293
294## Check if all necessary programs are available. ##
295
296# Programs that are in /bin or /usr/bin.
297Programs='
298 basename
299 cat
300 chown
301 dd
302 dirname
303 expr
304 fold
305 grep
306 gzip
307 hexdump
308 ls
309 mkdir
310 mktemp
311 mount
312 printf
313 pwd
314 rm
315 sed
316 sort
317 tr
318 umount
319 wc'
320
321# Programs that are in /usr/sbin or /sbin.
322Programs_SBIN='
323 blkid
324 fdisk
325 filefrag
326 losetup'
327
328
329Check_Prog=1;
330
331for Program in ${Programs} ${Programs_SBIN}; do
332 if [ $(type ${Program} > /dev/null 2>&1 ; echo $?) -ne 0 ] ; then
333 echo "\"${Program}\" could not be found." >&2;
334 Check_Prog=0;
335 fi
336done
337
338
339
340## Can we decompress a LZMA stream? ##
341#
342# The Grub2 (v1.99-2.00) core_dir string is contained in a LZMA stream.
343# See if we have xz or lzma installed to decompress the stream.
344#
345
346if [ $(type xz > /dev/null 2>&1 ; echo $?) -eq 0 ] ; then
347 UNLZMA='xz --format=lzma --decompress';
348elif [ $(type lzma > /dev/null 2>&1 ; echo $?) -eq 0 ] ; then
349 UNLZMA='lzma -cd';
350else
351 UNLZMA='none';
352fi
353
354
355
356## Do we have gawk or (a recent) mawk? ##
357#
358# If we don't have gawk, look for "mawk v1.3.4" or newer.
359#
360
361if [ $(type gawk > /dev/null 2>&1 ; echo $?) -eq 0 ] ; then
362 # Set awk binary to gawk.
363 AWK='gawk';
364elif [ $(type mawk > /dev/null 2>&1 ; echo $?) -eq 0 ] ; then
365 MAWK_version="$(mawk -W version 2>&1)";
366 MAWK_version="${MAWK_version:0:10}";
367
368 if [ "${MAWK_version}" = 'mawk 1.3.3' ]; then
369 printf '"mawk v1.3.3" has known bugs.\nInstall "mawk v1.3.4" or newer from http://invisible-island.net/mawk/ or use "gawk" instead.\n' >&2;
370 Check_Prog=0;
371 else
372 # Set awk binary to mawk (version 1.3.4 or higher).
373 AWK='mawk';
374 fi
375else
376 printf 'Install "gawk" or "mawk v1.3.4" (or newer) from http://invisible-island.net/mawk/.\n' >&2;
377 Check_Prog=0;
378fi
379
380
381
382if [ ${Check_Prog} -eq 0 ] ; then
383 printf '\nPlease install the missing program(s) and run Boot Info Script again.\n' >&2;
384 exit 1;
385fi
386
387
388
389## List of folders which might contain files used for chainloading. ##
390
391Boot_Codes_Dir='
392 /
393 /NST/
394 '
395
396
397
398## List of files whose names will be displayed, if found. ##
399
400Boot_Prog_Normal='
401 /bootmgr /BOOTMGR
402 /boot/bcd /BOOT/bcd /Boot/bcd /boot/BCD /BOOT/BCD /Boot/BCD
403 /Windows/System32/winload.exe /WINDOWS/system32/winload.exe /WINDOWS/SYSTEM32/winload.exe /windows/system32/winload.exe
404 /Windows/System32/Winload.exe /WINDOWS/system32/Winload.exe /WINDOWS/SYSTEM32/Winload.exe /windows/system32/Winload.exe
405 /grldr /GRLDR /grldr.mbr /GRLDR.MBR
406 /ntldr /NTLDR
407 /NTDETECT.COM /ntdetect.com
408 /NTBOOTDD.SYS /ntbootdd.sys
409 /wubildr /ubuntu/winboot/wubildr
410 /wubildr.mbr /ubuntu/winboot/wubildr.mbr
411 /ubuntu/disks/root.disk
412 /ubuntu/disks/home.disk
413 /ubuntu/disks/swap.disk
414 /core.img /grub/core.img /boot/grub/core.img
415 /grub/i386-pc/core.img /boot/grub/i386-pc/core.img
416 /grub2/core.img /boot/grub2/core.img
417 /grub2/i386-pc/core.img /boot/grub2/i386-pc/core.img
418 /burg/core.img /boot/burg/core.img
419 /ldlinux.sys /syslinux/ldlinux.sys /boot/syslinux/ldlinux.sys
420 /extlinux.sys /extlinux/extlinux.sys /boot/extlinux/extlinux.sys
421 /boot/map /map
422 /DEFAULT.MNU /default.mnu
423 /IO.SYS /io.sys
424 /MSDOS.SYS /msdos.sys
425 /KERNEL.SYS /kernel.sys
426 /DELLBIO.BIN /dellbio.bin /DELLRMK.BIN /dellrmk.bin
427 /COMMAND.COM /command.com
428 '
429
430Boot_Prog_Fat='
431 /bootmgr
432 /boot/bcd
433 /Windows/System32/winload.exe
434 /grldr
435 /grldr.mbr
436 /ntldr
437 /freeldr.sys
438 /NTDETECT.COM
439 /NTBOOTDD.SYS
440 /wubildr
441 /wubildr.mbr
442 /ubuntu/winboot/wubildr
443 /ubuntu/winboot/wubildr.mbr
444 /ubuntu/disks/root.disk
445 /ubuntu/disks/home.disk
446 /ubuntu/disks/swap.disk
447 /core.img /grub/core.img /boot/grub/core.img
448 /grub/i386-pc/core.img /boot/grub/i386-pc/core.img
449 /grub2/core.img /boot/grub2/core.img
450 /grub2/i386-pc/core.img /boot/grub2/i386-pc/core.img
451 /burg/core.img /boot/burg/core.img
452 /ldlinux.sys /syslinux/ldlinux.sys /boot/syslinux/ldlinux.sys
453 /extlinux.sys /extlinux/extlinux.sys /boot/extlinux/extlinux.sys
454 /boot/map /map
455 /DEFAULT.MNU
456 /IO.SYS
457 /MSDOS.SYS
458 /KERNEL.SYS
459 /DELLBIO.BIN /DELLRMK.BIN
460 /COMMAND.COM
461 '
462
463
464
465## List of files whose contents will be displayed. ##
466
467Boot_Files_Normal='
468 /menu.lst /grub/menu.lst /boot/grub/menu.lst /NST/menu.lst
469 /grub.cfg /grub/grub.cfg /boot/grub/grub.cfg /grub2/grub.cfg /boot/grub2/grub.cfg
470 /custom.cfg /grub/custom.cfg /boot/grub/custom.cfg /grub2/custom.cfg /boot/grub2/custom.cfg
471 /burg.cfg /burg/burg.cfg /boot/burg/burg.cfg
472 /grub.conf /grub/grub.conf /boot/grub/grub.conf /grub2/grub.conf /boot/grub2/grub.conf
473 /ubuntu/disks/boot/grub/menu.lst /ubuntu/disks/install/boot/grub/menu.lst /ubuntu/winboot/menu.lst
474 /boot.ini /BOOT.INI /Boot.ini
475 /etc/fstab
476 /etc/lilo.conf /lilo.conf
477 /syslinux.cfg /syslinux/syslinux.cfg /boot/syslinux/syslinux.cfg
478 /extlinux.conf /extlinux/extlinux.conf /boot/extlinux/extlinux.conf
479 /grldr /grub.exe
480 '
481
482Boot_Files_Fat='
483 /menu.lst /grub/menu.lst /boot/grub/menu.lst /NST/menu.lst
484 /grub.cfg /grub/grub.cfg /boot/grub/grub.cfg /grub2/grub.cfg /boot/grub2/grub.cfg
485 /custom.cfg /grub/custom.cfg /boot/grub/custom.cfg /grub2/custom.cfg /boot/grub2/custom.cfg
486 /burg.cfg /burg/burg.cfg /boot/burg/burg.cfg
487 /grub.conf /grub/grub.conf /boot/grub/grub.conf /grub2/grub.conf /boot/grub2/grub.conf
488 /ubuntu/disks/boot/grub/menu.lst /ubuntu/disks/install/boot/grub/menu.lst /ubuntu/winboot/menu.lst
489 /boot.ini
490 /freeldr.ini
491 /etc/fstab
492 /etc/lilo.conf /lilo.conf
493 /syslinux.cfg /syslinux/syslinux.cfg /boot/syslinux/syslinux.cfg
494 /extlinux.conf /extlinux/extlinux.conf /boot/extlinux/extlinux.conf
495 /grldr /grub.exe
496 '
497
498
499## List of files whose end point (in GiB / GB) will be displayed. ##
500
501GrubError18_Files='
502 menu.lst grub/menu.lst boot/grub/menu.lst NST/menu.lst
503 ubuntu/disks/boot/grub/menu.lst
504 grub.conf grub/grub.conf boot/grub/grub.conf grub2/grub.conf boot/grub2/grub.conf
505 grub.cfg grub/grub.cfg boot/grub/grub.cfg grub2/grub.cfg boot/grub2/grub.cfg
506 burg.cfg burg/burg.cfg boot/burg/burg.cfg
507 core.img grub/core.img boot/grub/core.img
508 grub/i386-pc/core.img boot/grub/i386-pc/core.img
509 grub2/core.img boot/grub2/core.img
510 grub2/i386-pc/core.img boot/grub2/i386-pc/core.img
511 burg/core.img boot/burg/core.img
512 stage2 grub/stage2 boot/grub/stage2
513 boot/vmlinuz* vmlinuz* ubuntu/disks/boot/vmlinuz*
514 boot/initrd* initrd* ubuntu/disks/boot/initrd*
515 boot/kernel*.img
516 initramfs* boot/initramfs*
517 '
518
519SyslinuxError_Files='
520 syslinux.cfg syslinux/syslinux.cfg boot/syslinux/syslinux.cfg
521 extlinux.conf extlinux/extlinux.conf boot/extlinux/extlinux.conf
522 ldlinux.sys syslinux/ldlinux.sys boot/syslinux/ldlinux.sys
523 extlinux.sys extlinux/extlinux.sys boot/extlinux/extlinux.sys
524 *.c32 syslinux/*.c32 boot/syslinux/*.c32
525 extlinux/*.c32 boot/extlinux/*.c32
526 '
527
528
529
530## Set output filename ##
531
532if [ ${stdout_output} -eq 1 ] ; then
533 # The LogFile name is not used when --stdout is specified.
534 LogFile="";
535elif ( [ ! -z "${LogFile_cmd}" ]) ; then
536 # The RESULTS filename is specified on the commandline.
537 LogFile=$(basename "${LogFile_cmd}");
538
539 # Directory where the RESULTS file will be stored.
540 Dir=$(dirname "${LogFile_cmd}");
541
542 # Check if directory exists.
543 if [ ! -d "${Dir}" ] ; then
544 echo "The directory \"${Dir}\" does not exist.";
545 echo 'Create the directory or specify another path for the output file.';
546 exit 1;
547 fi
548
549 Dir=$(cd "${Dir}"; pwd);
550 LogFile="${Dir}/${LogFile}";
551else
552 # Directory containing this script.
553 Dir=$(cd "$(dirname "$0")"; pwd);
554
555 # Set ${Dir} to the home folder of the current user if the script is
556 # in one of the system folders.
557 # This allows placement of the script in /bin, /sbin, /usr/bin, ...
558 # while still having a normal location to write the output file to.
559
560 for systemdir in /bin /boot /cdrom /dev /etc /lib /lost+found /opt /proc /sbin /selinux /srv /sys /usr /var; do
561 if [ $(expr "${Dir}" : ${systemdir}) -ne 0 ] ; then
562 Dir="${HOME}";
563 break;
564 fi
565 done
566
567 # To avoid overwriting existing files, look for a non-existing file:
568 # RESULT.txt, RESULTS1.txt, RESULTS2.txt, ...
569
570 LogFile="${Dir}/RESULTS";
571
572 while ( [ -e "${LogFile}${j}.txt" ] ) ; do
573 if [ x"${j}" = x'' ]; then
574 j=0;
575 fi
576 j=$((${j}+1));
577 done
578
579 LogFile="${LogFile}${j}.txt"; ## The RESULTS file. ##
580fi
581
582
583
584## Redirect stdout to RESULT File ##
585#
586# exec 6>&1
587# exec > "${LogFile}"
588
589
590
591## Create temporary directory ##
592
593Folder=$(mktemp -t -d BootInfo-XXXXXXXX);
594
595
596
597## Create temporary filenames. ##
598
599cd ${Folder}
600Log=${Folder}/Log # File to record the summary.
601Log1=${Folder}/Log1 # Most of the information which is not part of
602 # the summary is recorded in this file.
603Error_Log=${Folder}/Error_Log # File to catch all unusal Standar Errors.
604Trash=${Folder}/Trash # File to catch all usual Standard Errors these
605 # messagges will not be included in the RESULTS.
606Mount_Error=${Folder}/Mount_Error # File to catch Mounting Errors.
607Unknown_MBR=${Folder}/Unknown_MBR # File to record all unknown MBR and Boot sectors.
608Tmp_Log=${Folder}/Tmp_Log # File to temporarily hold some information.
609core_img_file=${Folder}/core_img # File to temporarily store an embedded core.img of grub2.
610core_img_file_unlzma=${Folder}/core_img_unlzma # File to temporarily store the uncompressed part of core.img of grub2.
611core_img_file_type_2=${Folder}/core_img_type_2 # File to temporarily store the core.img module of type 2
612PartitionTable=${Folder}/PT # File to store the Partition Table.
613FakeHardDrives=${Folder}/FakeHD # File to list devices which seem to have no corresponding drive.
614BLKID=${Folder}/BLKID # File to store the output of blkid.
615GRUB200_Module=${Folder}/GRUB200_Module # File to store current grub2 module
616
617
618
619## Redirect all standard error to the file Error_Log. ##
620
621exec 2> ${Error_Log};
622
623
624
625## List of all hard drives ##
626#
627# Support more than 26 drives.
628
629All_Hard_Drives=$(ls /dev/hd[a-z] /dev/hd[a-z][a-z] /dev/sd[a-z] /dev/sd[a-z][a-z] /dev/xvd[a-z] /dev/vd[a-z] /dev/vd[a-z][a-z] 2>> ${Trash});
630
631
632## Add found RAID disks to list of hard drives. ##
633
634if [ $(type dmraid >> ${Trash} 2>> ${Trash} ; echo $?) -eq 0 ] ; then
635 InActiveDMRaid=$(dmraid -si -c);
636
637 if [ x"${InActiveDMRaid}" = x"no raid disks" ] || [ x"${InActiveDMRaid}" = x"no block devices found" ] ; then
638 InActiveDMRaid='';
639 fi
640
641 if [ x"${InActiveDMRaid}" != x'' ] ; then
642 dmraid -ay ${InActiveDMRaid} >> ${Trash};
643 fi
644
645 All_DMRaid=$(dmraid -sa -c);
646 if [ x"${All_DMRaid}" != x"no raid disks" ] && [ x"${All_DMRaid}" != x"no block devices found" ] ; then
647 All_DMRaid=$(echo "{All_DMRaid}" | ${AWK} '{ print "/dev/mapper/"$0 }');
648 All_Hard_Drives="${All_Hard_Drives} ${All_DMRaid}";
649 fi
650fi
651
652
653
654## Arrays to hold information about Partitions: ##
655#
656# name, starting sector, ending sector, size in sector, partition type,
657# filesystem type, UUID, kind(Logical, Primary, Extended), harddrive,
658# boot flag, parent (for logical partitions), label,
659# system(the partition id according the partition table),
660# the device associated with the partition.
661
662declare -a NamesArray StartArray EndArray SizeArray TypeArray FileArray UUIDArray KindArray DriveArray BootArray ParentArray LabelArray SystemArray DeviceArray;
663
664
665## Arrays to hold information about the harddrives. ##
666
667declare -a HDName FirstPartion LastPartition HDSize HDMBR HDHead HDTrack HDCylinder HDPT HDStart HDEnd HDUUID;
668
669
670## Array for hard drives formatted as filesystem. ##
671
672declare -a FilesystemDrives;
673
674
675
676PI=-1; ## Counter for the identification number of a partition. (each partition gets unique number) ##
677HI=0; ## Counter for the identification number of a hard drive. (each hard drive gets unique number) ##
678PTFormat='%-10s %4s%14s%14s%14s %3s %s\n'; ## standard format (hexdump) to use for partition table. ##
679
680
681
682## Get total number of blocks on a device. ##
683#
684# Sometimes "fdisk -s" seems to malfunction or isn't supported (busybox fdisk),
685# so use "sfdisk -s" if available.
686# If sfdisk isn't available, calculate the number of blocks from the number of
687# sectors (divide by 2).
688
689fdisks () {
690 if [ $(type sfdisk >> ${Trash} 2>> ${Trash} ; echo $?) -eq 0 ] ; then
691 sfdisk -s "$1" 2>> ${Trash};
692 else
693 # Calculate the number of blocks from the number of sectors (divide by 2).
694 fdisk -lu "$1" 2>> ${Trash} | ${AWK} '$0 ~ /, .*, .*, .*/ { print $(NF - 1) / 2 }';
695 fi
696}
697
698
699
700## A function which checks whether a file is on a mounted partition. ##
701
702# List of mount points for devices: also allow mount points with spaces.
703
704MountPoints=$(mount \
705 | ${AWK} -F "\t" '{ if ( ($1 ~ "^/dev") && ($3 != "/") ) { sub(" on ", "\t", $0); sub(" type ", "\t", $0); print $2 } }' \
706 | sort -u);
707
708
709FileNotMounted () {
710 local File=$1 curmp=$2;
711
712 IFS_OLD="${IFS}"; # Save original IFS.
713 IFS=$'\012'; # Set IFS temporarily to newline only, so mount points with spaces can be processed too.
714
715 for mp in ${MountPoints}; do
716 if [ $(expr match "${File}" "${mp}/" ) -ne 0 ] && [ "${mp}" != "${curmp}" ] ; then
717 IFS="${IFS_OLD}"; # Restore original IFS.
718 return 1;
719 fi
720 done
721
722 IFS="${IFS_OLD}"; # Restore original IFS.
723 return 0;
724}
725
726
727
728## Function which converts the two digit hexcode to the partition type. ##
729#
730# The following list is taken from sfdisk -T and
731# http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
732# is work in progress.
733
734HexToSystem () {
735 local type=$1 system;
736
737 case ${type} in
738 0) system='Empty';;
739 1) system='FAT12';;
740 2) system='XENIX root';;
741 3) system='XENIX /usr';;
742 4) system='FAT16 <32M';;
743 5) system='Extended';;
744 6) system='FAT16';;
745 7) system='NTFS / exFAT / HPFS';;
746 8) system='AIX bootable';;
747 9) system='AIX data';;
748 a) system='OS/2 Boot Manager';;
749 b) system='W95 FAT32';;
750 c) system='W95 FAT32 (LBA)';;
751 e) system='W95 FAT16 (LBA)';;
752 f) system='W95 Extended (LBA)';;
753 10) system='OPUS';;
754 11) system='Hidden FAT12';;
755 12) system='Compaq diagnostics';;
756 14) system='Hidden FAT16 < 32M';;
757 16) system='Hidden FAT16';;
758 17) system='Hidden NTFS / HPFS';;
759 18) system='AST SmartSleep';;
760 1b) system='Hidden W95 FAT32';;
761 1c) system='Hidden W95 FAT32 (LBA)';;
762 1e) system='Hidden W95 FAT16 (LBA)';;
763 24) system='NEC DOS';;
764 27) system='Hidden NTFS (Recovery Environment)';;
765 2a) system='AtheOS File System';;
766 2b) system='SyllableSecure';;
767 32) system='NOS';;
768 35) system='JFS on OS/2';;
769 38) system='THEOS';;
770 39) system='Plan 9';;
771 3a) system='THEOS';;
772 3b) system='THEOS Extended';;
773 3c) system='PartitionMagic recovery';;
774 3d) system='Hidden NetWare';;
775 40) system='Venix 80286';;
776 41) system='PPC PReP Boot';;
777 42) system='SFS';;
778 44) system='GoBack';;
779 45) system='Boot-US boot manager';;
780 4d) system='QNX4.x';;
781 4e) system='QNX4.x 2nd part';;
782 4f) system='QNX4.x 3rd part';;
783 50) system='OnTrack DM';;
784 51) system='OnTrack DM6 Aux1';;
785 52) system='CP/M';;
786 53) system='OnTrack DM6 Aux3';;
787 54) system='OnTrack DM6 DDO';;
788 55) system='EZ-Drive';;
789 56) system='Golden Bow';;
790 57) system='DrivePro';;
791 5c) system='Priam Edisk';;
792 61) system='SpeedStor';;
793 63) system='GNU HURD or SysV';;
794 64) system='Novell Netware 286';;
795 65) system='Novell Netware 386';;
796 70) system='DiskSecure Multi-Boot';;
797 74) system='Scramdisk';;
798 75) system='IBM PC/IX';;
799 78) system='XOSL filesystem';;
800 80) system='Old Minix';;
801 81) system='Minix / old Linux';;
802 82) system='Linux swap / Solaris';;
803 83) system='Linux';;
804 84) system='OS/2 hidden C: drive';;
805 85) system='Linux extended';;
806 86) system='NTFS volume set';;
807 87) system='NTFS volume set';;
808 88) system='Linux plaintext';;
809 8a) system='Linux Kernel (AiR-BOOT)';;
810 8d) system='Free FDISK hidden Primary FAT12';;
811 8e) system='Linux LVM';;
812 90) system='Free FDISK hidden Primary FAT16 <32M';;
813 91) system='Free FDISK hidden Extended';;
814 92) system='Free FDISK hidden Primary FAT16';;
815 93) system='Amoeba/Accidently Hidden Linux';;
816 94) system='Amoeba bad block table';;
817 97) system='Free FDISK hidden Primary FAT32';;
818 98) system='Free FDISK hidden Primary FAT32 (LBA)';;
819 9a) system='Free FDISK hidden Primary FAT16 (LBA)';;
820 9b) system='Free FDISK hidden Extended (LBA)';;
821 9f) system='BSD/OS';;
822 a0) system='IBM Thinkpad hibernation';;
823 a1) system='Laptop hibernation';;
824 a5) system='FreeBSD';;
825 a6) system='OpenBSD';;
826 a7) system='NeXTSTEP';;
827 a8) system='Darwin UFS';;
828 a9) system='NetBSD';;
829 ab) system='Darwin boot';;
830 af) system='HFS / HFS+';;
831 b0) system='BootStar';;
832 b1 | b3) system='SpeedStor / QNX Neutrino Power-Safe';;
833 b2) system='QNX Neutrino Power-Safe';;
834 b4 | b6) system='SpeedStor';;
835 b7) system='BSDI fs';;
836 b8) system='BSDI swap';;
837 bb) system='Boot Wizard hidden';;
838 bc) system='Acronis BackUp';;
839 be) system='Solaris boot';;
840 bf) system='Solaris';;
841 c0) system='CTOS';;
842 c1) system='DRDOS / secured (FAT-12)';;
843 c2) system='Hidden Linux (PowerBoot)';;
844 c3) system='Hidden Linux Swap (PowerBoot)';;
845 c4) system='DRDOS secured FAT16 < 32M';;
846 c5) system='DRDOS secured Extended';;
847 c6) system='DRDOS secured FAT16';;
848 c7) system='Syrinx';;
849 cb) system='DR-DOS secured FAT32 (CHS)';;
850 cc) system='DR-DOS secured FAT32 (LBA)';;
851 cd) system='CTOS Memdump?';;
852 ce) system='DR-DOS FAT16X (LBA)';;
853 cf) system='DR-DOS secured EXT DOS (LBA)';;
854 d0) system='REAL/32 secure big partition';;
855 da) system='Non-FS data / Powercopy Backup';;
856 db) system='CP/M / CTOS / ...';;
857 dd) system='Dell Media Direct';;
858 de) system='Dell Utility';;
859 df) system='BootIt';;
860 e1) system='DOS access';;
861 e3) system='DOS R/O';;
862 e4) system='SpeedStor';;
863 e8) system='LUKS';;
864 eb) system='BeOS BFS';;
865 ec) system='SkyOS';;
866 ee) system='GPT';;
867 ef) system='EFI (FAT-12/16/32)';;
868 f0) system='Linux/PA-RISC boot';;
869 f1) system='SpeedStor';;
870 f2) system='DOS secondary';;
871 f4) system='SpeedStor';;
872 fb) system='VMware VMFS';;
873 fc) system='VMware VMswap';;
874 fd) system='Linux raid autodetect';;
875 fe) system='LANstep';;
876 ff) system='Xenix Bad Block Table';;
877 *) system='Unknown';;
878 esac
879
880 echo "${system}";
881}
882
883
884
885## Function to convert GPT's Partition Type. ##
886#
887# List from http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs
888#
889# ABCDEFGH-IJKL-MNOP-QRST-UVWXYZabcdef is stored as
890# GHEFCDAB-KLIJ-OPMN-QRST-UVWXYZabcdef (without the dashes)
891#
892# For easy generation of the following list:
893# - Save list in a file "Partition_type_GUIDs.txt" in the folowing format:
894#
895# Partition Type (OS) <TAB> GUID
896# Partition Type (OS) <TAB> GUID
897# Partition Type (OS) <TAB> GUID
898#
899# - Then run the following:
900#
901# gawk -F '\t' '{ GUID=tolower($2); printf " %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s) system=\"%s\";;\n", substr(GUID,7,1), substr(GUID,8,1), substr(GUID,5,1), substr(GUID,6,1), substr(GUID,3,1), substr(GUID,4,1), substr(GUID,1,1), substr(GUID,2,1), substr(GUID,12,1), substr(GUID,13,1), substr(GUID,10,1), substr(GUID,11,1), substr(GUID,17,1), substr(GUID,18,1), substr(GUID,15,1), substr(GUID,16,1), substr(GUID,20,4), substr(GUID,25,12), $1 } END { print " *) system='-';" }' Partition_type_GUIDs.txt
902#
903# - Some GUIDs are not unique for one OS. To find them, you can run:
904#
905# gawk -F "\t" '{print $2}' GUID_Partition_Table_list.txt | sort | uniq -d | grep -f - GUID_Partition_Table_list.txt
906#
907# Basic data partition (Windows) EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
908# Data partition (Linux) EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
909# ZFS (Mac OS X) 6A898CC3-1DD2-11B2-99A6-080020736631
910# /usr partition (Solaris) 6A898CC3-1DD2-11B2-99A6-080020736631
911#
912
913UUIDToSystem () {
914 local type=$1 system;
915
916 case ${type} in
917 00000000000000000000000000000000) system='Unused entry';;
918 41ee4d02e733d3119d690008c781f39f) system='MBR partition scheme';;
919 28732ac11ff8d211ba4b00a0c93ec93b) system='EFI System partition';;
920 4861682149646f6e744e656564454649) system='BIOS Boot partition';;
921 dee2bfd3af3ddf11ba40e3a556d89593) system="Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)";;
922
923 ## GUIDs that are not unique for one OS ##
924 a2a0d0ebe5b9334487c068b6b72699c7) system='Data partition (Windows/Linux)';;
925 c38c896ad21db21199a6080020736631) system='ZFS (Mac OS X) or /usr partition (Solaris)';;
926
927 ## Windows GUIDs ##
928 16e3c9e35c0bb84d817df92df00215ae) system='Microsoft Reserved Partition (Windows)';;
929 # Same GUID as old GUID for "Basic data partition (Linux)"
930 # a2a0d0ebe5b9334487c068b6b72699c7) system='Basic data partition (Windows)';;
931 aac808588f7ee04285d2e1e90434cfb3) system='Logical Disk Manager (LDM) metadata partition (Windows)';;
932 a0609baf3114624fbc683311714a69ad) system='Logical Disk Manager (LDM) data partition (Windows)';;
933 a4bb94ded106404da16abfd50179d6ac) system='Windows Recovery Environment (Windows)';;
934 90fcaf377def964e91c32d7ae055b174) system='IBM General Parallel File System (GPFS) partition (Windows)';;
935
936 ## HP-UX GUIDs ##
937 1e4c8975eb3ad311b7c17b03a0000000) system='Data partition (HP-UX)';;
938 28e7a1e2e332d611a6827b03a0000000) system='Service Partition (HP-UX)';;
939
940 ## Linux GUIDs ##
941 # Same GUID as "Basic data partition (Windows)" GUID
942 # a2a0d0ebe5b9334487c068b6b72699c7) system='Data partition (Linux)';;
943 # New GUID to avoid that Linux partitions show up as unformatted partitions in Windows.
944 af3dc60f838472478e793d69d8477de4) system='Data partition (Linux)';;
945 0f889da1fc053b4da006743f0f84911e) system='RAID partition (Linux)';;
946 6dfd5706aba4c44384e50933c84b4f4f) system='Swap partition (Linux)';;
947 79d3d6e607f5c244a23c238f2a3df928) system='Logical Volume Manager (LVM) partition (Linux)';;
948 3933a68d0700c060c436083ac8230908) system='Reserved (Linux)';;
949
950 ## FreeBSD GUIDs ##
951 9d6bbd83417fdc11be0b001560b84f0f) system='Boot partition (FreeBSD)';;
952 b47c6e51cf6ed6118ff800022d09712b) system='Data partition (FreeBSD)';;
953 b57c6e51cf6ed6118ff800022d09712b) system='Swap partition (FreeBSD)';;
954 b67c6e51cf6ed6118ff800022d09712b) system='Unix File System (UFS) partition (FreeBSD)';;
955 b87c6e51cf6ed6118ff800022d09712b) system='Vinum volume manager partition (FreeBSD)';;
956 ba7c6e51cf6ed6118ff800022d09712b) system='ZFS partition (FreeBSD)';;
957
958 ## Mac OS X GUIDs ##
959 005346480000aa11aa1100306543ecac) system='Hierarchical File System Plus (HFS+) partition (Mac OS X)';;
960 005346550000aa11aa1100306543ecac) system='Apple UFS (Mac OS X)';;
961 # c38c896ad21db21199a6080020736631) system='ZFS (Mac OS X)';;
962 444941520000aa11aa1100306543ecac) system='Apple RAID partition (Mac OS X)';;
963 444941524f5faa11aa1100306543ecac) system='Apple RAID partition offline (Mac OS X)';;
964 746f6f420000aa11aa1100306543ecac) system='Apple Boot partition (Mac OS X)';;
965 6562614c006caa11aa1100306543ecac) system='Apple Label (Mac OS X)';;
966 6f6365526576aa11aa1100306543ecac) system='Apple TV Recovery partition (Mac OS X)';;
967 726f74536761aa11aa1100306543ecac) system="Apple Core Storage (i.e. Lion FileVault) partition (Mac OS X)";;
968
969 ## Solaris GUIDs ##
970 45cb826ad21db21199a6080020736631) system='Boot partition (Solaris)';;
971 4dcf856ad21db21199a6080020736631) system='Root partition (Solaris)';;
972 6fc4876ad21db21199a6080020736631) system='Swap partition (Solaris)';;
973 2b648b6ad21db21199a6080020736631) system='Backup partition (Solaris)';;
974 # c38c896ad21db21199a6080020736631) system='/usr partition (Solaris)';;
975 e9f28e6ad21db21199a6080020736631) system='/var partition (Solaris)';;
976 39ba906ad21db21199a6080020736631) system='/home partition (Solaris)';;
977 a583926ad21db21199a6080020736631) system='Alternate sector (Solaris)';;
978 3b5a946ad21db21199a6080020736631) system='Reserved partition (Solaris)';;
979 d130966ad21db21199a6080020736631) system='Reserved partition (Solaris)';;
980 6707986ad21db21199a6080020736631) system='Reserved partition (Solaris)';;
981 7f23966ad21db21199a6080020736631) system='Reserved partition (Solaris)';;
982 c72a8d6ad21db21199a6080020736631) system='Reserved partition (Solaris)';;
983
984 ## NetBSD GUIDs ##
985 328df4490eb1dc11b99b0019d1879648) system='Swap partition (NetBSD)';;
986 5a8df4490eb1dc11b99b0019d1879648) system='FFS partition (NetBSD)';;
987 828df4490eb1dc11b99b0019d1879648) system='LFS partition (NetBSD)';;
988 aa8df4490eb1dc11b99b0019d1879648) system='RAID partition (NetBSD)';;
989 c419b52d0fb1dc11b99b0019d1879648) system='Concatenated partition (NetBSD)';;
990 ec19b52d0fb1dc11b99b0019d1879648) system='Encrypted partition (NetBSD)';;
991
992 ## ChromeOS GUIDs ##
993 5d2a3afe324fa741b725accc3285a309) system="ChromeOS kernel";;
994 02e2b83c7e3bdd478a3c7ff2a13cfcec) system="ChromeOS rootfs";;
995 3d750a2e489eb0438337b15192cb1b5e) system="ChromeOS future use";;
996
997 ## Haiku GUIDs ##
998 31534642a33bf110802a4861696b7521) system="Haiku BFS (Haiku)";;
999
1000 ## MidnightBSD GUIDs ##
1001 5ee4d5857c23e111b4b3e89a8f7fc3a7) system="Boot partition (MidnightBSD) ";;
1002 5ae4d5857c23e111b4b3e89a8f7fc3a7) system="Data partition (MidnightBSD)";;
1003 5be4d5857c23e111b4b3e89a8f7fc3a7) system="Swap partition (MidnightBSD)";;
1004 8bef94037e23e111b4b3e89a8f7fc3a7) system="Unix File System (UFS) partition (MidnightBSD)";;
1005 5ce4d5857c23e111b4b3e89a8f7fc3a7) system="Vinum volume manager partition (MidnightBSD)";;
1006 5de4d5857c23e111b4b3e89a8f7fc3a7) system="ZFS partition (MidnightBSD)";;
1007
1008 *) system='-';
1009 echo 'Unknown GPT Partiton Type' >> ${Unknown_MBR};
1010 echo ${type} >> ${Unknown_MBR};;
1011 esac
1012
1013 echo "${system}";
1014}
1015
1016
1017
1018## Function which inserts a comma every third digit of a number. ##
1019
1020InsertComma () {
1021 echo $1 | sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta';
1022}
1023
1024
1025
1026## Function to read 4 bytes starting at $1 of device $2 and convert result to decimal. ##
1027
1028Read4Bytes () {
1029 local start=$1 device=$2;
1030
1031 echo $(hexdump -v -s ${start} -n 4 -e '4 "%u"' ${device});
1032}
1033
1034
1035
1036## Function to read 8 bytes starting at $1 of device $2 and convert result to decimal. ##
1037
1038Read8Bytes () {
1039 local start=$1 device=$2;
1040 local first4 second4;
1041
1042 # Get ${first4} and ${second4} bytes at once.
1043 eval $(hexdump -v -s ${start} -n 8 -e '1/4 "first4=%u; " 1/4 "second4=%u"' ${device});
1044
1045 echo $(( ${second4} * 4294967296 + ${first4} ));
1046}
1047
1048
1049
1050## Functions to pretty print blkid output. ##
1051
1052BlkidFormat='%-16s %-38s %-10s %s\n';
1053
1054BlkidTag () {
1055 echo $(blkid -s $2 -o value $1 2>> ${Trash});
1056}
1057
1058
1059
1060PrintBlkid () {
1061 local part=$1 suffix=$2;
1062
1063 if [ x"$(blkid ${part} 2> ${Tmp_Log})" != x'' ] ; then
1064 printf "${BlkidFormat}" "${part}" "$(BlkidTag ${part} UUID)" "$(BlkidTag ${part} TYPE)" "$(BlkidTag ${part} LABEL)" >> ${BLKID}${suffix};
1065 else
1066 # blkid -p is not available on all systems.
1067 # This contructs makes sure the "usage" message is not displayed, but catches the "ambivalent" error.
1068 blkid -p "${part}" 2>&1 | grep "^${part}" >> ${BLKID}${suffix};
1069 fi
1070}
1071
1072
1073
1074## Read and display the partition table and check the partition table for errors. ##
1075#
1076# This function can be applied iteratively so extended partiton tables can also be processed.
1077#
1078# Function arguments:
1079#
1080# - arg 1: HI = HI of hard drive
1081# - arg 2: StartEx = start sector of the extended Partition
1082# - arg 3: N = number of partitions in table (4 for regular PT, 2 for logical
1083# - arg 4: PT_file = file for storing the partition table
1084# - arg 5: format = display format to use for displaying the partition table
1085# - arg 6: EPI = PI of the primary extended partition containing the extended partition.
1086# ( equals "" for hard drive)
1087# - arg 7: LinuxIndex = Last linux index assigned (the number in sdXY).
1088
1089ReadPT () {
1090 local HI=$1 StartEx=$2 N=$3 PT_file=$4 format=$5 EPI=$6 Base_Sector;
1091 local LinuxIndex=$7 boot size start end type drive system;
1092 local i=0 boot_hex label limit MBRSig;
1093
1094 drive=${HDName[${HI}]};
1095 limit=${HDSize[${HI}]};
1096
1097 dd if=${drive} skip=${StartEx} of=${Tmp_Log} count=1 2>> ${Trash};
1098
1099 MBRSig=$(hexdump -v -s 510 -n 2 -e '"%04x"' ${Tmp_Log});
1100
1101 [[ "${MBRSig}" != 'aa55' ]] && echo 'Invalid MBR Signature found.' >> ${PT_file};
1102
1103 if [[ ${StartEx} -lt ${limit} ]] ; then
1104 # set Base_Sector to 0 for hard drive, and to the start sector of the
1105 # primary extended partition otherwise.
1106 [[ x"${EPI}" = x'' ]] && Base_Sector=0 || Base_Sector=${StartArray[${EPI}]};
1107
1108 for (( i=0; i < N; i++ )) ; do
1109 dd if=${drive} skip=${StartEx} of=${Tmp_Log} count=1 2>> ${Trash};
1110
1111 boot_hex=$(hexdump -v -s $((446+16*${i})) -n 1 -e '"%02x"' ${Tmp_Log});
1112
1113 case ${boot_hex} in
1114 00) boot=' ';;
1115 80) boot='* ';;
1116 *) boot='?';;
1117 esac
1118
1119 # Get amd set: partition type, partition start, and partition size.
1120 eval $(hexdump -v -s $((450+16*${i})) -n 12 -e '1/1 "type=%x; " 3/1 "tmp=%x; " 1/4 "start=%u; " 1/4 "size=%u"' ${Tmp_Log});
1121
1122 if [[ ${size} -ne 0 ]] ; then
1123 if ( ( [ "${type}" = '5' ] || [ "${type}" = 'f' ] ) && [ ${Base_Sector} -ne 0 ] ) ; then
1124 # start sector of an extended partition is relative to the
1125 # start sector of an primary extended partition.
1126 start=$((${start}+${Base_Sector}));
1127
1128 if [[ ${i} -eq 0 ]] ; then
1129 echo 'Extended partition linking to another extended partition.' >> ${PT_file};
1130 fi
1131
1132 ReadPT ${HI} ${start} 2 ${PT_file} "${format}" ${EPI} ${LinuxIndex};
1133 else
1134 ((PI++));
1135
1136 if [[ "${type}" = '5' || "${type}" = 'f' ]] ; then
1137 KindArray[${PI}]='E';
1138 else
1139 # Start sector of a logical partition is relative to the
1140 # start sector of directly assocated extented partition.
1141 start=$((${start}+${StartEx}));
1142 [[ ${Base_Sector} -eq 0 ]] && KindArray[${PI}]='P' || KindArray[${PI}]='L';
1143 fi
1144
1145 LinuxIndex=$((${LinuxIndex}+1));
1146 end=$((${start}+${size}-1));
1147
1148 [[ "${HDPT[${HI}]}" = 'BootIt' ]] && label="${NamesArray[${EPI}]}_" || label=${drive};
1149
1150 system=$(HexToSystem ${type});
1151
1152 printf "${format}" "${label}${LinuxIndex}" "${boot}" $(InsertComma ${start}) "$(InsertComma ${end})" "$(InsertComma ${size})" "${type}" "${system}" >> ${PT_file};
1153
1154 NamesArray[${PI}]="${label}${LinuxIndex}";
1155 StartArray[${PI}]=${start};
1156 EndArray[${PI}]=${end};
1157 TypeArray[${PI}]=${type};
1158 SystemArray[${PI}]="${system}";
1159 SizeArray[${PI}]=${size};
1160 BootArray[${PI}]="${boot}";
1161 DriveArray[${PI}]=${HI};
1162 ParentArray[${PI}]=${EPI};
1163
1164 ( [[ x"${EPI}" = x'' ]] || [[ x"${DeviceArray[${EPI}]}" != x'' ]] ) && DeviceArray[${PI}]=${drive}${LinuxIndex};
1165
1166 if [[ "${type}" = '5' || "${type}" = 'f' ]] ; then
1167 ReadPT ${HI} ${start} 2 ${PT_file} "${format}" ${PI} 4;
1168 fi
1169 fi
1170
1171 elif ( [ ${Base_Sector} -ne 0 ] && [ ${i} -eq 0 ] ) ; then
1172 echo 'Empty Partition.' >> ${PT_file};
1173 else
1174 LinuxIndex=$((${LinuxIndex}+1));
1175 fi
1176 done
1177 else
1178 echo 'EBR refers to a location outside the hard drive.' >> ${PT_file};
1179 fi
1180}
1181
1182
1183
1184## Read the GPT partition table (GUID, EFI) ##
1185#
1186# Function arguments:
1187#
1188# - arg 1: HI = HI of hard drive
1189# - arg 2: GPT_file = file for storing the GPT partition table
1190
1191ReadEFI () {
1192 local HI=$1 GPT_file=$2 drive size N=0 i=0 format label PRStart start end type size system;
1193 local attrs attrstr attrs_other j;
1194
1195 drive="${HDName[${HI}]}";
1196 format='%-10s %5s %14s%14s%14s %s\n';
1197
1198 printf "${format}" 'Partition' 'Attrs' 'Start Sector' 'End Sector' '# of Sectors' 'System' >> ${GPT_file};
1199
1200 HDStart[${HI}]=$( Read8Bytes 552 ${drive});
1201 HDEnd[${HI}]=$( Read8Bytes 560 ${drive});
1202 HDUUID[${HI}]=$( hexdump -v -s 568 -n 16 -e '/1 "%02x"' ${drive});
1203 PRStart=$( Read8Bytes 584 ${drive});
1204 N=$( Read4Bytes 592 ${drive});
1205 PRStart=$(( ${PRStart}*512));
1206 PRSize=$( Read4Bytes 596 ${drive});
1207
1208 for (( i = 0; i < N; i++ )) ; do
1209 type=$(hexdump -v -s $((${PRStart}+${PRSize}*${i})) -n 16 -e '/1 "%02x"' ${drive});
1210
1211 if [ "${type}" != '00000000000000000000000000000000' ] ; then
1212 ((PI++));
1213
1214 start=$(Read8Bytes $((${PRStart}+32+${PRSize}*${i})) ${drive});
1215 end=$( Read8Bytes $((${PRStart}+40+${PRSize}*${i})) ${drive});
1216
1217 size=$((${end}-${start}+1));
1218 system=$(UUIDToSystem ${type});
1219 label=${drive}$((${i}+1));
1220
1221 # Partition attributes are 8 bytes long and bash arithmetic is signed.
1222 # High bits are used by Windows which automatically overflows computed
1223 # 64 bit number. As we are interested in low bits only, just check it
1224 # and output the rest verbatim if present.
1225 attrs=$(hexdump -v -s $((${PRStart}+48+${PRSize}*${i})) -n 1 -e '/1 "%02x"' ${drive});
1226 attrs_other=$(hexdump -v -s $((${PRStart}+49+${PRSize}*${i})) -n 7 -e '/1 "%02x"' ${drive});
1227
1228 if (( 0x${attrs} & 1 )) ; then
1229 attrstr='R';
1230 else
1231 attrstr=' ';
1232 fi
1233
1234 if (( 0x${attrs} & 2 )) ; then
1235 attrstr="N${attrstr}";
1236 else
1237 attrstr=" ${attrstr}";
1238 fi
1239
1240 if (( 0x${attrs} & 4 )) ; then
1241 attrstr="B${attrstr}";
1242 else
1243 attrstr=" ${attrstr}";
1244 fi
1245
1246 if (( 0x${attrs} & 8 )) || [ ${attrs_other} != '00000000000000' ] ; then
1247 attrstr="+$attrstr";
1248 echo >> ${Unknown_MBR};
1249 echo "${label}: unknown GPT attributes" >> ${Unknown_MBR};
1250 for (( j = 12; j >= 0; j -= 2 )) ; do
1251 printf '%s' ${attrs_other:j:2} >> ${Unknown_MBR}
1252 done
1253 echo ${attrs} >> ${Unknown_MBR}
1254 fi
1255
1256 printf "${format}" "${label}" "${attrstr}" "$(InsertComma ${start})" "$(InsertComma ${end})" "$(InsertComma ${size})" "${system}" >> ${GPT_file};
1257
1258 NamesArray[${PI}]=${label};
1259 DeviceArray[${PI}]=${label};
1260 StartArray[${PI}]=${start};
1261 TypeArray[${PI}]=${type};
1262 SizeArray[${PI}]=${size};
1263 SystemArray[${PI}]=${system};
1264 EndArray[${PI}]=${end};
1265 DriveArray[${PI}]=${HI};
1266 KindArray[${PI}]='P';
1267 ParentArray[${PI}]='';
1268 fi
1269 done
1270 echo >> ${GPT_file};
1271 echo 'Attributes: R=Required, N=No Block IO, B=Legacy BIOS Bootable, +=More bits set' >> ${GPT_file};
1272}
1273
1274
1275
1276## Read the Master Partition Table of BootIt NG. ##
1277#
1278# Function arguments:
1279#
1280# - arg 1: HI = HI of hard drive
1281# - arg 2: MPT_file = file for storing the MPT
1282
1283ReadEMBR () {
1284 local HI=$1 MPT_file=$2 drive size N=0 i=0 BINGIndex label start end type format;
1285 local BINGUnknown system StoredPI FirstPI=${FirstPartition[$1]} LastPI=${PI} New;
1286
1287 drive="${HDName[${HI}]}";
1288 format='%-18s %4s%14s%14s%14s %3s %-15s %3s %2s\n';
1289
1290 printf "${format}" 'Partition' 'Boot' 'Start Sector' 'End Sector' '# of Sectors' 'Id' 'System' 'Ind' '?' >> ${MPT_file};
1291
1292 N=$(hexdump -v -s 534 -n 1 -e '"%u"' ${drive});
1293
1294 for (( i = 0; i < N; i++ )) ; do
1295 New=1;
1296 BINGUnknown=$(hexdump -v -s $((541+28*${i})) -n 1 -e '"%x"' ${drive});
1297 start=$( hexdump -v -s $((542+28*${i})) -n 4 -e '4 "%u"' ${drive});
1298 end=$( hexdump -v -s $((546+28*${i})) -n 4 -e '4 "%u"' ${drive});
1299 BINGIndex=$( hexdump -v -s $((550+28*${i})) -n 1 -e '"%u"' ${drive});
1300 type=$( hexdump -v -s $((551+28*${i})) -n 1 -e '"%x"' ${drive});
1301 size=$(( ${end}-${start}+1));
1302 label=$( hexdump -v -s $((552+28*${i})) -n 15 -e '"%_u"' ${drive}| sed -e 's/nul[^$]*//');
1303 system=$( HexToSystem ${type});
1304
1305 printf "${format}" "${label}" "-" "$(InsertComma ${start})" "$(InsertComma ${end})" "$(InsertComma ${size})" "${type}" "${system}" "${BINGIndex}" "${BINGUnknown}" >> ${MPT_file};
1306
1307 StoredPI=${PI};
1308
1309 for (( j = FirstPI; j <= LastPI; j++ )); do
1310 if (( ${StartArray[${j}]} == ${start} )) ; then
1311 PI=${j};
1312 New=0;
1313 break;
1314 fi
1315 done
1316
1317 if [ ${New} -eq 1 ] ; then
1318 ((PI++));
1319 StoredPI=${PI};
1320 StartArray[${PI}]=${start};
1321 TypeArray[${PI}]=${type};
1322 SizeArray[${PI}]=${size};
1323 SystemArray[${PI}]=${system};
1324 EndArray[${PI}]=${end};
1325 DriveArray[${PI}]=${HI};
1326 fi
1327
1328 NamesArray[${PI}]=${label};
1329
1330 if ( [ ${type} = 'f' ] || [ ${type} = '5' ] ) ; then
1331 KindArray[${PI}]='E';
1332 ParentArray[${PI}]=${PI};
1333 ReadPT ${HI} ${start} 2 ${MPT_file} "${format}" ${PI} 4;
1334 else
1335 KindArray[${PI}]='P';
1336 ParentArray[${PI}]='';
1337 fi
1338
1339 PI=${StoredPI};
1340
1341 done
1342}
1343
1344
1345
1346## Check partition table for errors. ##
1347#
1348# This function checks whether:
1349# - there are any overlapping partitions
1350# - the logical partitions are inside the extended partition
1351#
1352# Function arguments:
1353#
1354# - arg 1: PI_first = PI of first partition to consider
1355# - arg 2: PI_last = PI of last partition to consider
1356# - arg 3: CHK_file = file for the error messages
1357# - arg 4: HI = HI of containing hard drive
1358
1359CheckPT () {
1360 local PI_first=$1 PI_last=$2 CHK_file=$3 HI=$4;
1361 local Si Ei Sj Ej Ki Kj i j k cyl track head cyl_bound sec_bound;
1362
1363 cyl=${HDCylinder[${HI}]};
1364 track=${HDTrack[${HI}]};
1365 head=${HDHead[${HI}]};
1366 cyl_bound=$((cyl * track * head));
1367 sec_bound=${HDSize[${HI}]};
1368
1369 for (( i = PI_first; i <= PI_last; i++ )); do
1370 Si=${StartArray[${i}]};
1371 Ei=${EndArray[${i}]};
1372 Ki=${KindArray[${i}]};
1373 Ni=${NamesArray[${i}]};
1374
1375 if [[ "${Ei}" -gt "${sec_bound}" ]] ; then
1376 echo "${Ni} ends after the last sector of ${HDName[${HI}]}" >> ${CHK_file};
1377 elif [[ "${Ei}" -gt "${cyl_bound}" ]] ; then
1378 echo "${Ni} ends after the last cylinder of ${HDName[${HI}]}" >> ${Trash};
1379 fi
1380
1381 if [[ ${Ki} = "L" ]] ; then
1382 k=${ParentArray[${i}]};
1383 Sk=${StartArray[${k}]};
1384 Ek=${EndArray[${k}]};
1385 Nk=${NamesArray[${k}]};
1386 [[ ${Si} -le ${Sk} || ${Ei} -gt ${Ek} ]] && echo "the logical partition ${Ni} is not contained in the extended partition ${Nk}" >> ${CHK_file};
1387 fi
1388
1389 for (( j = i+1; j <= PI_last; j++ )); do
1390 Sj=${StartArray[${j}]};
1391 Ej=${EndArray[${j}]};
1392 Kj=${KindArray[${j}]};
1393 Nj=${NamesArray[${j}]};
1394
1395 ( !( ( [ "${Ki}" = 'L' ] && [ "${Kj}" = 'E' ] ) || ( [ "${Ki}" = 'E' ] && [ "${Kj}" = 'L' ] ) ) \
1396 && ( ( [ "${Si}" -lt "${Sj}" ] && [ "${Sj}" -lt "${Ei}" ] ) || ( [ "${Sj}" -lt "${Si}" ] && [ "${Si}" -lt "${Ej}" ] ) ) ) \
1397 && echo "${Ni} overlaps with ${Nj}" >> ${CHK_file};
1398
1399 done
1400 done
1401}
1402
1403
1404
1405## Syslinux ##
1406#
1407# Determine the exact Syslinux version ("SYSLINUX - version - date"), display
1408# the offset to the second stage, check the internal checksum (if not correct,
1409# the ldlinux.sys file, probably moved), display the directory to which
1410# Syslinux is installed.
1411
1412syslinux_info () {
1413 local partition=$1;
1414
1415 # Magic number used by Syslinux:
1416 local LDLINUX_MAGIC='fe02b23e';
1417
1418 local LDLINUX_BSS LDLINUX_SECTOR2 ADV_2SECTORS;
1419 local sect1ptr0_offset sect1ptr0 sect1ptr1 tmp;
1420 local magic_offset syslinux_version syslinux_dir;
1421
1422 # Patch area variables:
1423 local pa_version pa_size pa_hexdump_format pa_magic pa_instance pa_data_sectors;
1424 local pa_adv_sectors pa_dwords pa_checksum pa_maxtransfer pa_epaoffset;
1425 local pa_ldl_sectors pa_dir_inode;
1426
1427 # Extended patch area variables:
1428 local epa_size epa_hexdump_format epa_advptroffset epa_diroffset epa_dirlen;
1429 local epa_subvoloffset epa_subvollen epa_secptroffset epa_secptrcnt;
1430 local epa_sect1ptr0 epa_sect1ptr1 epa_raidpatch epa_syslinuxbanner;
1431
1432 # ADV magic numbers:
1433 local ADV_MAGIC_HEAD='a52f2d5a'; # Head signature
1434 local ADV_MAGIC_TAIL='64bf28dd'; # Tail signature
1435 local ADV_MAGIC_CHECKSUM=$((0xa3041767)); # Magic used for calculation ADV checksum
1436
1437 # ADV variables:
1438 local ADVoffset ADV_calculated_checksum ADV_read_checksum ADVentry_offset;
1439 local tag='999' tag_len label;
1440
1441 local csum;
1442
1443
1444
1445 # Clear previous Syslinux message string.
1446 Syslinux_Msg='';
1447
1448 # Read first 512 bytes of partition and convert to hex (ldlinux.bss)
1449 LDLINUX_BSS=$(hexdump -v -n512 -e '/1 "%02x"' ${partition});
1450
1451 # Look for LDLINUX_MAGIC: bytes 504-507
1452 if [ "${LDLINUX_BSS:1008:8}" = "${LDLINUX_MAGIC}" ] ; then
1453 # Syslinux 4.04-pre5 and higher.
1454 pa_version=4; # Syslinux 4.xx patch area
1455
1456 # The offset of Sect1Load in LDLINUX_BSS can be found by doing a
1457 # bitwise XOR of bytes 508-509 (little endian) with 0x1b << 9.
1458 # sect1ptr0_offset starts 2 bytes furter than Sect1Load.
1459 sect1ptr0_offset=$(( ( 0x${LDLINUX_BSS:1018:2}${LDLINUX_BSS:1016:2} ^ ( 0x1b << 9 ) ) + 2 ));
1460
1461 # Get "boot sector offset" (in sectors) of sector 1 ptr LSW: sect1ptr0
1462 # Get "boot sector offset" (in sectors) of sector 1 ptr MSW: sect1ptr1
1463 eval $(hexdump -v -s ${sect1ptr0_offset} -n 10 -e '1/4 "sect1ptr0=%u; " 1/2 "tmp=%u; " 1/4 "sect1ptr1=%u;"' ${partition});
1464
1465 else
1466 # Check if bytes 508-509 = "7f00".
1467 if [ "${LDLINUX_BSS:1016:4}" = '7f00' ] ; then
1468 # Syslinux 3.xx
1469 pa_version=3; # Syslinux 3.xx patch area
1470
1471 # Get "boot sector offset" (in sectors) of sector 1 ptr LSW: sect1ptr0
1472 eval $(hexdump -v -s 504 -n 4 -e '1/4 "sect1ptr0=%u;"' ${partition});
1473 else
1474 # Syslinux 4.00 - Syslinux 4.04-pre4.
1475 pa_version=4; # Syslinux 4.xx patch area
1476
1477 # Search for offset to sect1ptr0 (only found in Syslinux 4.xx)
1478 # 66 b8 xx xx xx xx 66 ba xx xx xx xx bb 00
1479 # [sect1ptr0] [sect1ptr1]
1480 #
1481 # Start searching for this hex string after the DOS superblock: byte 0x5a = 90
1482 eval $(echo ${LDLINUX_BSS:180:844} \
1483 | ${AWK} '{ mask_offset=match($0,"66b8........66ba........bb00"); \
1484 if (mask_offset == "0") { print "sect1ptr0_offset=0;" } \
1485 else { print "sect1ptr0_offset=" (mask_offset -1 ) / 2 + 2 + 90 } }');
1486
1487 if [ ${sect1ptr0_offset} -ne 0 ] ; then
1488 # Syslinux 4.00 - Syslinux 4.04-pre4.
1489
1490 # Get "boot sector offset" (in sectors) of sector 1 ptr LSW: sect1ptr0
1491 # Get "boot sector offset" (in sectors) of sector 1 ptr MSW: sect1ptr1
1492 eval $(hexdump -v -s ${sect1ptr0_offset} -n 10 -e '1/4 "sect1ptr0=%u; " 1/2 "tmp=%u; " 1/4 "sect1ptr1=%u;"' ${partition});
1493 else
1494 Syslinux_Msg='No evidence that this is realy a Syslinux boot sector.';
1495 return;
1496 fi
1497 fi
1498 fi
1499
1500 Syslinux_Msg="Syslinux looks at sector ${sect1ptr0} of ${partition} for its second stage.";
1501
1502 # Start reading 0.5MiB (more than enough) from second sector of the Syslinux
1503 # bootloader (= first sector of ldlinux.sys).
1504 dd if=${partition} of=${Tmp_Log} skip=${sect1ptr0} count=1000 bs=512 2>> ${Trash};
1505
1506 # Get second sector of the Syslinux bootloader (= first sector of ldlinux.sys)
1507 # and convert to hex.
1508 LDLINUX_SECTOR2=$(hexdump -v -n 512 -e '/1 "%02x"' ${Tmp_Log});
1509
1510 # Look for LDLINUX_MAGIC (8 bytes aligned) in sector 2 of the Syslinux bootloader.
1511 for (( magic_offset = $((0x10)); magic_offset < $((0x50)); magic_offset = magic_offset + 8 )); do
1512 if [ "${LDLINUX_SECTOR2:$(( ${magic_offset} * 2 )):8}" = ${LDLINUX_MAGIC} ] ; then
1513
1514 if [ ${pa_version} -eq 4 ] ; then
1515 # Syslinux 4.xx patch area.
1516
1517 # Patch area size: 4+4+2+2+4+4+2+2 = 4*4 + 4*2 = 24 bytes
1518 pa_size='24';
1519
1520 # Get pa_magic, pa_instance, pa_data_sectors, pa_adv_sectors, pa_dwords, pa_checksum, pa_maxtransfer and pa_epaoffset.
1521 pa_hexdump_format='1/4 "pa_magic=0x%04x; " 1/4 "pa_instance=0x%04x; " 1/2 "pa_data_sectors=%u; " 1/2 "pa_adv_sectors=%u; " 1/4 "pa_dwords=0x%u; " 1/4 "pa_checksum=0x%04x; " 1/2 "pa_maxtransfer=%u; " 1/2 "pa_epaoffset=%u;"';
1522
1523 eval $(hexdump -v -s ${magic_offset} -n ${pa_size} -e "${pa_hexdump_format}" ${Tmp_Log});
1524
1525 else
1526 # Syslinux 3.xx patch area.
1527
1528 # Patch area size: 4+4+2+2+4+4 = 4*4 + 2*2 = 20 bytes
1529 pa_size='20';
1530
1531 # Get pa_magic, pa_instance, pa_dwords, pa_ldl_sectors and pa_checksum.
1532 # - pa_dwords: Total dwords starting at ldlinux_sys not including ADVs.
1533 # - pa_ldl_sectors: Number of sectors - (bootsec + sector2) but including any ADVs.
1534 pa_hexdump_format='1/4 "pa_magic=0x%04x; " 1/4 "pa_instance=0x%04x; " 1/2 "pa_dwords=%u; " 1/2 "pa_ldl_sectors=%u; " 1/4 "pa_checksum=0x%04x; " 1/4 "pa_dir_inode=%u;"';
1535
1536 eval $(hexdump -v -s ${magic_offset} -n ${pa_size} -e "${pa_hexdump_format}" ${Tmp_Log});
1537
1538 # Calulate pa_data_sectors: number of sectors (not including ldlinux.bss = first sector of Syslinux).
1539 # - divide by 128 (128 dwords / 512 byte sector)
1540 pa_data_sectors=$(( ${pa_dwords} / 128 ));
1541
1542 # If total dwords is not exactly a multiple of 128, round up the number of sectors (add 1).
1543 if [ $(( ${pa_dwords}%128 )) -ne 0 ] ; then
1544 pa_data_sectors=$(( ${pa_data_sectors} + 1 ));
1545 fi
1546
1547
1548 # Some Syslinux 4.00-pre?? releases are different:
1549 # - have Syslinux 3.xx signature: bytes 508-509 = "7f00".
1550 # - have the "boot sector offset" (in sectors) of sector 1 ptr LSW (bytes 504-507)
1551 # for sect1ptr0, like Syslinux 3.xx.
1552 # - have like Syslinux 4.xx, the same location for pa_data_sectors.
1553 #
1554 # If pa_dwords is less than 1024, it contains the value of pa_data_sectors:
1555 # - if less and pa_words would really be pa_words: ldlinux.sys would be smaller than 4 kiB
1556 # - if more and pa_words would really be pa_data_sectors: ldlinux.sys would be more than 500 kiB
1557
1558 if [ ${pa_dwords} -lt 1024 ] ; then
1559 pa_data_sectors=${pa_dwords};
1560 fi
1561
1562 fi
1563
1564
1565 # Get the "SYSLINUX - version - date" string.
1566 syslinux_version=$(hexdump -v -e '"%_p"' -s 2 -n $(( ${magic_offset} - 2 )) ${Tmp_Log});
1567 syslinux_version="${syslinux_version% \.*}";
1568
1569 # Overwrite the "boot sector type" variable, which was set before calling this function,
1570 # with a more exact Syslinux version number.
1571 BST="${syslinux_version}";
1572
1573
1574 # Check integrity of Syslinux:
1575 # - Checksum starting at ldlinux.sys, stopping before the ADV part.
1576 # - checksum start = LDLINUX_MAGIC - [sum of dwords].
1577 # - add each dword to the checksum value.
1578 # - the value of the checksum after adding all dwords of ldlinux.sys should be 0.
1579
1580 csum=$(hexdump -v -n $(( ${pa_data_sectors} * 512)) -e '/4 "%u\n"' ${Tmp_Log} \
1581 | ${AWK} 'BEGIN { csum=4294967296-1051853566 } { csum=(csum + $1)%4294967296 } END {print csum}' );
1582
1583 if [ ${csum} -ne 0 ] ; then
1584 Syslinux_Msg="${Syslinux_Msg} The integrity check of Syslinux failed.";
1585 return;
1586 fi
1587
1588
1589 if [ ${pa_version} -eq 4 ] ; then
1590 # Extended patch area size: 11*2 = 22 bytes
1591 epa_size='22';
1592
1593 # Get epa_advptroffset, epa_diroffset, epa_dirlen, epa_subvoloffset, epa_subvollen,
1594 # epa_secptroffset, epa_secptrcnt, epa_sect1ptr0, epa_sect1ptr1 and epa_raidpatch.
1595 epa_hexdump_format='1/2 "epa_advptroffset=%u; " 1/2 "epa_diroffset=%u; " 1/2 "epa_dirlen=%u; " 1/2 "epa_subvoloffset=%u; " 1/2 "epa_subvollen=%u; " 1/2 "epa_secptroffset=%u; " 1/2 "epa_secptrcnt=%u; " 1/2 "epa_sect1ptr0=%u; " 1/2 "epa_sect1ptr1=%u; " 1/2 "epa_raidpatch=%u; " 1/2 "epa_syslinuxbanner=%u;"';
1596
1597 eval $(hexdump -v -s ${pa_epaoffset} -n ${epa_size} -e "${epa_hexdump_format}" ${Tmp_Log});
1598
1599 # Get the Syslinux install directory.
1600 syslinux_dir=$(hexdump -v -e '"%_p"' -s ${epa_diroffset} -n ${epa_dirlen} ${Tmp_Log});
1601 syslinux_dir=${syslinux_dir%%\.*};
1602
1603 Syslinux_Msg="${Syslinux_Msg} ${syslinux_version:0:8} is installed in the ${syslinux_dir} directory.";
1604
1605
1606 # In Syslinux 4.04 and higher, the whole Syslinux banner is not in the first sector of ldlinux.sys.
1607 # Only the "SYSLINUX - version" string is still located in the first sector.
1608 # epa_syslinuxbanner points to the whole "SYSLINUX - version - date" string.
1609
1610 if [ ${epa_syslinuxbanner} -lt $(( ${pa_data_sectors} * 512 )) ] ; then
1611 # Get the "SYSLINUX - version - date" string.
1612 tmp=$(hexdump -v -e '"%_p"' -s $(( ${epa_syslinuxbanner} + 2 )) -n 100 ${Tmp_Log});
1613
1614
1615 # Check if we have Syslinux 4.04 or higher, which suppport the epa_syslinuxbanner field
1616 # by comparing the first 8 bytes ("SYSLINUX") of the Syslinux banner from sector 1 with
1617 # the 8 bytes to which epa_syslinuxbanner points.
1618
1619 if [ x"${tmp:0:8}" = x"${syslinux_version:0:8}" ] ; then
1620 syslinux_version="${tmp%%\.No DEFAULT*}";
1621
1622 # Overwrite the "boot sector type" variable, which was set before calling this function,
1623 # with a more exact Syslinux version number.
1624 BST="${syslinux_version}";
1625 fi
1626 fi
1627
1628
1629
1630 # ADV stuff starts here.
1631
1632 if [ ${pa_adv_sectors} -ne 2 ] ; then
1633 Syslinux_Msg="${Syslinux_Msg} There are ${pa_adv_sectors} ADV sectors instead of 2.";
1634 return;
1635 fi
1636
1637 # Get the ADV offset.
1638 ADVoffset=$(( pa_data_sectors * 512 ));
1639
1640 # Get the ADV.
1641 ADV_2SECTORS=$(hexdump -v -s ${ADVoffset} -n 1024 -e '/1 "%02x"' ${Tmp_Log});
1642
1643 # Check if the 2 ADV sectors are exactly the same.
1644 if [ "${ADV_2SECTORS:0:1024}" != "${ADV_2SECTORS:1024:1024}" ] ; then
1645 Syslinux_Msg="${Syslinux_Msg} The 2 ADV sectors are not the same (corrupt).";
1646 return;
1647 fi
1648
1649 # Check if the ADV area contains the ADV head and tail magic.
1650 if ( [ "${ADV_2SECTORS:0:8}" = "${ADV_MAGIC_HEAD}" ] && [ "${ADV_2SECTORS:1016:8}" = "${ADV_MAGIC_TAIL}" ] ) ; then
1651
1652 # Caculate the ADV checksum.
1653 ADV_calculated_checksum=$(hexdump -v -s $(( ${ADVoffset} + 8 )) -n $((512 - 3*4)) -e '/4 "%u\n"' ${Tmp_Log} \
1654 | ${AWK} 'BEGIN { csum='${ADV_MAGIC_CHECKSUM}' } { csum=(csum - $1 + 4294967296)%4294967296 } END { print csum }');
1655
1656 ADV_read_checksum=$(hexdump -s $(( ${ADVoffset} + 4 )) -n 4 -e '/4 "%u\n"' ${Tmp_Log});
1657
1658
1659 if [ ${ADV_calculated_checksum} -eq ${ADV_read_checksum} ] ; then
1660
1661 # Get the info stored in the ADV area:
1662 #
1663 # maximum 2 entries can be stored in the ADV, which have the following layout:
1664 # - byte 1 : tag ==> 0 = no entry, 1 = boot-once entry, 2 = menu-save entry
1665 # - byte 2 : tag_len ==> length of label string
1666 # - byte 3 - (3 + tag_len) : label ==> label name that will be used
1667
1668 # First entry starts a offset 8.
1669 ADVentry_offset=8;
1670
1671 until eval $(hexdump -s $(( ${ADVoffset} + ${ADVentry_offset} )) -n $((512 - 3*4)) \
1672 -e '1/1 "tag=%u; " 1/1 "tag_len=%u; label='\''" 498 "%_p"' ${Tmp_Log};
1673 printf "'");
1674 [ ${tag} -eq 0 ] ; do
1675
1676
1677 if [ ${tag_len} -gt 0 ] ; then
1678 label=${label:0:${tag_len}};
1679 fi
1680
1681 case ${tag} in
1682 1) Syslinux_Msg="${Syslinux_Msg} ${syslinux_version:0:8}'s ADV is set to boot label \"${label}\" next boot only.";;
1683 2) Syslinux_Msg="${Syslinux_Msg} ${syslinux_version:0:8}'s ADV is set to boot label \"${label}\" by default.";;
1684 esac
1685
1686 # Adjust the ADVentry_offset, so it points to the next entry.
1687 ADVentry_offset=$(( ${ADVentry_offset} + ${tag_len} + 2 ));
1688
1689 done
1690 else
1691 Syslinux_Msg="${Syslinux_Msg} The integrity check of the ADV area failed.";
1692 fi
1693 else
1694 Syslinux_Msg="${Syslinux_Msg} The ADV head and tail magic bytes were not found.";
1695 fi
1696 fi
1697
1698 return;
1699 fi
1700 done
1701
1702 # LDLINUX_MAGIC not found.
1703 Syslinux_Msg="${Syslinux_Msg} It is very unlikely that Syslinux is (still) installed. The second stage could not be found.";
1704
1705}
1706
1707
1708
1709## Grub Legacy ##
1710#
1711# Determine the embeded location of stage 2 in a stage 1 file,
1712# look for the stage 2 and, if found, determine the
1713# the location and the path of the embedded menu.lst.
1714
1715stage2_loc () {
1716 local stage1="$1" HI;
1717
1718 offset=$(hexdump -v -s 68 -n 4 -e '4 "%u"' "${stage1}");
1719 dr=$(hexdump -v -s 64 -n 1 -e '1/1 "%u"' "${stage1}");
1720 pa='T';
1721 Grub_Version='';
1722
1723 for HI in ${!HDName[@]}; do
1724 hdd=${HDName[${HI}]};
1725
1726 if [ ${offset} -lt ${HDSize[HI]} ] ; then
1727 tmp=$(dd if=${hdd} skip=${offset} count=1 2>> ${Trash} | hexdump -v -n 4 -e '"%x"');
1728
1729 if [[ "${tmp}" = '3be5652' || "${tmp}" = 'bf5e5652' ]] ; then
1730 # stage2 files were found.
1731 dd if=${hdd} skip=$((offset+1)) count=1 of=${Tmp_Log} 2>> ${Trash};
1732 pa=$(hexdump -v -s 10 -n 1 -e '"%d"' ${Tmp_Log});
1733 stage2_hdd=${hdd};
1734 Grub_String=$(hexdump -v -s 18 -n 94 -e '"%_u"' ${Tmp_Log});
1735 Grub_Version=$(echo ${Grub_String} | sed -e 's/nul[^$]*//');
1736 BL=${BL}${Grub_Version};
1737 menu=$(echo ${Grub_String} | sed -e 's/[^\/]*//' -e 's/nul[^$]*//');
1738 menu=${menu%% *};
1739 fi
1740 fi
1741 done
1742
1743 dr=$((${dr}-127));
1744 Stage2_Msg="looks at sector ${offset}";
1745
1746 if [ "${dr}" -eq 128 ] ; then
1747 Stage2_Msg="${Stage2_Msg} of the same hard drive";
1748 else
1749 Stage2_Msg="${Stage2_Msg} on boot drive #${dr}";
1750 fi
1751
1752 Stage2_Msg="${Stage2_Msg} for the stage2 file";
1753
1754 if [ "${pa}" = "T" ] ; then
1755 # no stage 2 file found.
1756 Stage2_Msg="${Stage2_Msg}, but no stage2 files can be found at this location.";
1757 else
1758 pa=$((${pa}+1));
1759 Stage2_Msg="${Stage2_Msg}. A stage2 file is at this location on ${stage2_hdd}. Stage2 looks on";
1760
1761 if [ "${pa}" -eq 256 ] ; then
1762 Stage2_Msg="${Stage2_Msg} the same partition";
1763 else
1764 Stage2_Msg="${Stage2_Msg} partition #${pa}";
1765 fi
1766
1767 Stage2_Msg="${Stage2_Msg} for ${menu}.";
1768 fi
1769}
1770
1771
1772
1773
1774## Grub2 ##
1775#
1776# Collect fragments of core.img using information encoded in the first
1777# block (diskboot.img).
1778#
1779
1780grub2_read_blocklist () {
1781 local hdd="$1";
1782 local core_img_file="$2";
1783
1784 local sector_nr_low sector_nr_high sector_nr fragment_size;
1785 local fragment_offset=1 block_list=500;
1786
1787 # Assemble fragments from "hdd" passed to grub2_info.
1788 # Each block list entry is 12 bytes long and consists of
1789 # 8 bytes = fragment start absolute disk offset in sectors of 512 bytes
1790 # 2 bytes = fragment size in sectors of 512 bytes
1791 # 2 bytes = memory segment to load fragment into
1792 # Entries start at the end of the first sector of core.img and
1793 # go down. End marker is all zeroes.
1794 #
1795 # Blocklists were changed to 64 bit in 2006, so all versions BIS detects
1796 # should have it.
1797 #
1798 # Older versions of hexdump do not support 8 byte integers, so read
1799 # high and low words separately.
1800
1801 while [ ${block_list} -gt 12 ] ; do
1802 sector_nr_low=$(hexdump -v -n 4 -s ${block_list} -e '1/4 "%u"' ${core_img_file});
1803 sector_nr_high=$(hexdump -v -n 4 -s $((block_list+4)) -e '1/4 "%u"' ${core_img_file});
1804 let "sector_nr = (sector_nr_high << 32) + sector_nr_low";
1805 if [ ${sector_nr} -eq 0 ] ; then
1806 return;
1807 fi
1808
1809 fragment_size=$(hexdump -v -n 2 -s $((block_list+8)) -e '1/2 "%u"' ${core_img_file});
1810
1811 dd if="${hdd}" of=${core_img_file} skip=${sector_nr} seek=${fragment_offset} count=${fragment_size} 2>> ${Trash} || return;
1812 let "fragment_offset += fragment_size";
1813 let "block_list -= 12";
1814 done
1815}
1816
1817## Grub2 ##
1818#
1819# Determine the embeded module name. This function implements manual
1820# parsing of ELF information to avoid dependency on binutils or similar.
1821#
1822
1823grub2_modname ()
1824{
1825 local modfile=$1;
1826 local file_size=$2;
1827 local e_ehsize sht_offset sht_entsize sht_num sht_shdrndx sht_strtab;
1828 local sht_strtabsize s_nameidx s_type s_name m_offset m_size;
1829 local i=0;
1830
1831 # ELF header is at least 52 bytes in size
1832 if [ "${file_size}" -lt 52 ] ; then
1833 return;
1834 fi
1835
1836 # ELF Magic + CLASS32 + LSB + VERSION
1837 if [ "$(hexdump -n 7 -e '4/1 "%02x" 3/1 "%x"' "${modfile}")" != '7f454c46111' ] ; then
1838 return;
1839 fi
1840
1841 # RELOCATABLE + MACHINE + VERSION
1842 if [ "$(hexdump -s 16 -n 8 -e '2/2 "%x" 1/4 "%x"' "${modfile}")" != '131' ] ; then
1843 return;
1844 fi
1845
1846 # ELF header size
1847 e_ehsize=$(hexdump -s 40 -n 2 -e '"%u"' "${modfile}")
1848 if [ "${e_ehsize}" -lt 52 -o "${e_ehsize}" -gt "${file_size}" ] ; then
1849 return;
1850 fi
1851
1852 # Offset of section headers table
1853 sht_offset=$(hexdump -s 32 -n 4 -e '"%u"' "${modfile}")
1854 if [ "${sht_offset}" -lt "${e_ehsize}" -o "${sht_offset}" -ge "${file_size}" ] ; then
1855 return;
1856 fi
1857
1858 # Size of section header
1859 sht_entsize=$(hexdump -s 46 -n 2 -e '"%u"' "${modfile}")
1860
1861 # Number of section headers
1862 sht_num=$(hexdump -s 48 -n 2 -e '"%u"' "${modfile}")
1863 if [ "${sht_entsize}" -eq 0 -o "${sht_num}" -eq 0 -o $((sht_offset + sht_entsize*sht_num)) -gt "${file_size}" ] ; then
1864 return;
1865 fi
1866
1867 # Index of section names string table
1868 sht_shdrndx=$(hexdump -s 50 -n 2 -e '"%u"' "${modfile}")
1869 if [ "${sht_shdrndx}" -ge "${sht_num}" ] ; then
1870 return;
1871 fi
1872
1873 # Offset of section names string table
1874 sht_strtab=$(hexdump -s $((sht_offset + $((sht_shdrndx*sht_entsize)) + 16)) -n 4 -e '"%u"' "${modfile}");
1875 if [ "${sht_strtab}" -lt "${e_ehsize}" -o "${sht_strtab}" -ge "${file_size}" ] ; then
1876 return;
1877 fi
1878
1879 # Size of section names string table
1880 sht_strtabsize=$(hexdump -s $((sht_offset + $((sht_shdrndx*sht_entsize)) + 20)) -n 4 -e '"%u"' "${modfile}");
1881 if [ "${sht_strtabsize}" -eq 0 -o "${sht_strtabsize}" -gt "$((file_size-sht_strtab))" ] ; then
1882 return;
1883 fi
1884
1885 while [ "${i}" -lt $((sht_entsize*sht_num)) ] ; do
1886 s_nameidx=$(hexdump -s $((sht_offset + i)) -n 4 -e '"%u"' "${modfile}");
1887 if [ "${s_nameidx}" -lt "${sht_strtabsize}" ] ; then
1888 s_type=$(hexdump -s $((sht_offset + i + 4)) -n 4 -e '"%u"' "${modfile}");
1889 # PROGBITS
1890 if [ "${s_type}" -eq 1 ] ; then
1891 s_name=$(hexdump -s $((sht_strtab + s_nameidx)) -n "${sht_strtabsize}" -e "1/${sht_strtabsize} \"%s\"" "${modfile}");
1892 if [ "${s_name}" = '.modname' ] ; then
1893 m_offset=$(hexdump -s $((sht_offset + i + 16)) -n 4 -e '"%u"' "${modfile}");
1894 m_size=$(hexdump -s $((sht_offset + i + 20)) -n 4 -e '"%u"' "${modfile}");
1895 if [ $((m_offset + m_size)) -lt "${file_size}" ] ; then
1896 hexdump -s "${m_offset}" -n "${m_size}" -e "/${m_size} \"%s\"" "${modfile}";
1897 return
1898 fi
1899 fi
1900 fi
1901 fi
1902 : $((i+=sht_entsize))
1903 done
1904
1905 # Display "???" as indication that parsing failed
1906 printf '%s' '???'
1907 return
1908}
1909
1910## Grub2 ##
1911#
1912# Determine the (embeded) location of core.img for a Grub2 boot.img file,
1913# determine the path of the grub2 directory and look for an embedded config file.
1914#
1915
1916grub2_info () {
1917 local stage1="$1" hdd="$2";
1918
1919 # When $grub2_version is "1.99-2.00", we want to override this value
1920 # with a more exact value later (needs to be a global variable).
1921 grub2_version="$3";
1922
1923 # Have we got plain file or need to collect full core.img from blocklists?
1924 local core_source="$4";
1925
1926 local sector_offset drive_offset directory_offset sector_nr drive_nr drive_nr_hex;
1927 local partition core_dir embedded_config HI magic core_img_found=0 embedded_config_found=0;
1928 local total_module_size kernel_image_size compressed_size offset_lzma lzma_uncompressed_size;
1929 local grub_module_info_offset grub_module_magic grub_modules_offset grub_modules_size;
1930 local grub_module_type grub_module_size grub_module_header_offset grub_modules_end_offset;
1931 local lzma_compressed_size reed_solomon_redundancy reed_solomon_length boot_dev boot_drive;
1932 local core_img_flavour='detect' modname all_modules need_core_prologue=0;
1933 local grub_module_header_next;
1934
1935 > ${core_img_file_type_2}
1936
1937 case "${grub2_version}" in
1938 1.96) sector_offset='68'; drive_offset='76'; directory_offset='553';;
1939 1.97-1.98) sector_offset='92'; drive_offset='100'; directory_offset='540';;
1940 1.99|1.99-2.00|2.00) sector_offset='92'; drive_offset='100';;
1941 esac
1942
1943 # Offset to core.img (in sectors).
1944 sector_nr=$(hexdump -v -s ${sector_offset} -n 4 -e '4 "%u"' "${stage1}" 2>> ${Trash});
1945
1946 # BIOS drive number on which grub2 looks for its second stage (=core.img):
1947 # - "0xff" means that grub2 will use the BIOS drive number passed via the DL register.
1948 # - if this value isn't "0xff", that value will used instead.
1949 # Since version 1.97 GRUB2 is using only 0xff. We cannot reliably determine BIOS numbers
1950 # anyway, so just skip core.img detection in this case.
1951 drive_nr_hex=$(hexdump -v -s ${drive_offset} -n 1 -e '"0x%02x"' "${stage1}" 2>> ${Trash});
1952 drive_nr=$(( ${drive_nr_hex} - 127 ));
1953
1954 if [ "${drive_nr_hex}" != '0xff' ] ; then
1955 Grub2_Msg="is configured to load core.img from BIOS drive ${drive_nr} (${drive_nr_hex}) instead of using the boot drive passed by the BIOS";
1956 return
1957 fi
1958
1959 Grub2_Msg="looks at sector ${sector_nr} of the same hard drive for core.img";
1960
1961
1962 for HI in ${!HDName[@]} ; do
1963 # If the drive name passed to grub2_info matches the drive name of the current
1964 # value of HDName, see if the sector offset to core.img is smaller than the
1965 # total number of sectors of that drive.
1966
1967 if [ ${hdd} = ${HDName[${HI}]} ] ; then
1968 if [ ${sector_nr} -lt ${HDSize[HI]} ] ; then
1969
1970 if [ "${core_source}" = 'file' ] ; then
1971 # Use "file" passed to grub2_info directly.
1972 dd if="${stage1}" of=${core_img_file} skip=${sector_nr} count=1024 2>> ${Trash};
1973 else
1974 # Use "hdd" passed to grub2_info.
1975 # First make sure to collect core.img fragments. Read the first block of
1976 # core.img and assemble it further from blocklists
1977 dd if="${hdd}" of=${core_img_file} skip=${sector_nr} count=1 2>> ${Trash};
1978 grub2_read_blocklist "${hdd}" ${core_img_file};
1979 fi
1980
1981 magic=$(hexdump -v -n 4 -e '/1 "%02x"' ${core_img_file});
1982
1983 # 5256be1b - upstream diskboot.S
1984 # 5256be6f - unknown
1985 # 52e82801 - Ubuntu diskboot.S with conditional message
1986 # 52bff481 - RHEL7 diskboot.S with patched out message
1987 # 5256be63 - trustedgrub2 1.4
1988 # 5256be56 - diskboot.S with mjg TPM patches (e.g. in openSUSE Tumbleweed)
1989
1990 case "${magic}" in
1991 '5256be1b'|'5256be6f'|'52e82801'|'52bff481'|'5256be63'|'5256be56')
1992 core_img_found=1;;
1993 esac
1994
1995 if [ ${core_img_found} -eq 1 ] ; then
1996
1997 if ( [ "${grub2_version}" = '1.99' ] || [ "${grub2_version}" = '1.99-2.00' ] || [ "${grub2_version}" = '2.00' ] ) ; then
1998 # Find the last 8 bytes of lzma_decode to find the offset of the lzma_stream:
1999 # - v1.99: "d1 e9 df fe ff ff 00 00"
2000 # - v2.00: "d1 e9 df fe ff ff 66 90" (pad bytes NOP)
2001 # "d1 e9 df fe ff ff 8d" (pad bytes LEA ...)
2002 #
2003 # arvidjaar@gmail.com:
2004 # final directive in startup_raw.S is .p2align 4 which
2005 # (at least using current GCC/GAS) adds lea instructions
2006 # (8d...). Exact format and length apparently depend on pad
2007 # size and may be on toolkit version. So just accept anything
2008 # starting with lea.
2009 #
2010 # FIXME what if it ends on exact 16 byte boundary?
2011
2012 eval $(hexdump -v -n 10000 -e '1/1 "%02x"' ${core_img_file} | \
2013 ${AWK} '{ found_at=match($0, "d1e9dffeffff" ); if (found_at == "0") { print "offset_lzma=0" } \
2014 else { print "offset_lzma=" ((found_at - 1 ) / 2 ) + 8 "; lzma_decode_last8bytes=" substr($0,found_at,16) ";" } }');
2015
2016 if [ "${grub2_version}" = '1.99-2.00' ] ; then
2017 if ( [ "${lzma_decode_last8bytes}" = "d1e9dffeffff6690" ] || [ "${lzma_decode_last8bytes:0:14}" = "d1e9dffeffff8d" ] ) ; then
2018 grub2_version='2.00';
2019 else
2020 grub2_version='1.99';
2021 fi
2022 fi
2023 else
2024 # Grub2 (v1.96 and v1.97-1.98).
2025 partition=$(hexdump -v -s 532 -n 1 -e '"%d"' ${core_img_file});
2026 core_dir=$(hexdump -v -s ${directory_offset} -n 64 -e '"%_u"' ${core_img_file} | sed 's/nul[^$]*//');
2027 fi
2028
2029 if [ "${grub2_version}" = '1.99' ] ; then
2030
2031 # For Grub2 (v1.99), the core_dir is just at the beginning of the compressed part of core.img.
2032
2033 # Get grub_total_module_size : byte 0x208-0x20b of embedded core.img ==> byte 520
2034 # Get grub_kernel_image_size : byte 0x20c-0x20f of embedded core.img ==> byte 524
2035 # Get grub_compressed_size : byte 0x210-0x213 of embedded core.img ==> byte 528
2036 # Get grub_install_dos_part : byte 0x214-0x218 of embedded core.img ==> byte 532 --> only 1 byte needed (partition)
2037
2038 eval $(hexdump -v -s 520 -n 13 -e '1/4 "total_module_size=%u; " 1/4 "kernel_image_size=%u; " 1/4 "compressed_size=%u; " 1 "partition=%d;"' ${core_img_file});
2039
2040
2041
2042 # Do we have xz or lzma installed?
2043 if [ "${UNLZMA}" != 'none' ] ; then
2044 if [ ${offset_lzma} -ne 0 ] ; then
2045
2046 # Correct the offset to the lzma stream, when 8 subsequent bytes of zeros are at the start of this offset.
2047 if [ $(hexdump -v -s ${offset_lzma} -n 8 -e '1/1 "%02x"' ${core_img_file}) = '0000000000000000' ] ; then
2048 offset_lzma=$(( ${offset_lzma} + 8 ));
2049 fi
2050
2051 # Calculate the uncompressed size to which the compressed lzma stream needs to be expanded.
2052 lzma_uncompressed_size=$(( ${total_module_size} + ${kernel_image_size} - ${offset_lzma} + 512 ));
2053
2054 # Make lzma header (13 bytes): ${lzma_uncompressed_size} must be displayed in little endian format.
2055 printf '\x5d\x00\x00\x01\x00'$( printf '%08x' $((${lzma_uncompressed_size} - ${offset_lzma} + 512 )) \
2056 | ${AWK} '{printf "\\x%s\\x%s\\x%s\\x%s", substr($0,7,2), substr($0,5,2), substr($0,3,2), substr($0,1,2)}' )'\x00\x00\x00\x00' > ${Tmp_Log};
2057
2058 # Get lzma_stream, add it after the lzma header and decompress it.
2059 dd if=${core_img_file} bs=${offset_lzma} skip=1 count=$((${lzma_uncompressed_size} / ${offset_lzma} + 1)) 2>> ${Trash} \
2060 | cat ${Tmp_Log} - | ${UNLZMA} 2>> ${Trash} > ${core_img_file_unlzma};
2061
2062 # Get core dir.
2063 core_dir=$( hexdump -v -n 64 -e '"%_c"' ${core_img_file_unlzma} );
2064 # Remove "\0"s at the end.
2065 core_dir="${core_dir%%\\0*}";
2066
2067
2068 # Offset of the grub_module_info structure in the uncompressed part.
2069 grub_module_info_offset=$(( ${kernel_image_size} - ${offset_lzma} + 512 ));
2070
2071 eval $(hexdump -v -n 12 -s ${grub_module_info_offset} -e '"grub_module_magic=" 4/1 "%_c" 1/4 "; grub_modules_offset=%u; " 1/4 "grub_modules_size=%u;"' ${core_img_file_unlzma});
2072
2073 # Check for the existence of the grub_module_magic.
2074 if [ x"${grub_module_magic}" = x'mimg' ] ; then
2075 # Embedded grub modules found.
2076 grub_modules_end_offset=$(( ${grub_module_info_offset} + ${grub_modules_size} ));
2077 grub_module_header_offset=$(( ${grub_module_info_offset} + ${grub_modules_offset} ));
2078
2079 # Traverse through the list of modules and check if it is a config module.
2080 while [ ${grub_module_header_offset} -lt ${grub_modules_end_offset} ] ; do
2081
2082 eval $(hexdump -v -n 8 -s ${grub_module_header_offset} -e '1/4 "grub_module_type=%u; " 1/4 "grub_module_size=%u;"' ${core_img_file_unlzma});
2083
2084 if [ ${grub_module_type} -eq 2 ] ; then
2085 # This module is an embedded config file.
2086 embedded_config_found=1;
2087
2088 embedded_config=$( hexdump -v -n $(( ${grub_module_size} - 8 )) -s $(( ${grub_module_header_offset} + 8 )) -e '"%_c"' ${core_img_file_unlzma} );
2089 # Remove "\0" at the end.
2090 embedded_config=$( printf "${embedded_config%\\0}" );
2091
2092 break;
2093 fi
2094
2095 grub_module_header_offset=$(( ${grub_module_header_offset} + ${grub_module_size} ));
2096
2097 done
2098 fi
2099 fi
2100 else
2101 # When xz or lzma isn't available, we can't get the core_dir, but we still can show some info.
2102 core_dir='??';
2103
2104 echo 'To be able to see for which directory Grub2 (v1.99) looks for, install "xz" or "lzma".' >&2;
2105 fi
2106 elif [ "${grub2_version}" = '2.00' ] ; then
2107
2108 # For Grub2 (v2.00), the core_dir is stored in the compressed part of core.img in the same
2109 # way as the modules and embedded config file.
2110
2111 # Get grub_compressed_size : byte 0x208-0x20b of embedded core.img ==> byte 520
2112 # Get grub_uncompressed_size : byte 0x20c-0x20f of embedded core.img ==> byte 524
2113 # Get grub_reed_solomon_redundancy : byte 0x210-0x213 of embedded core.img ==> byte 528
2114 # Get grub_no_reed_solomon_length : byte 0x214-0x217 of embedded core.img ==> byte 532
2115 # Get grub_boot_dev : byte 0x218-0x21a of embedded core.img ==> byte 536 ( should also contain the grub_boot_drive field )
2116 # Get grub_boot_drive : byte 0x21b of embedded core.img ==> byte 539
2117
2118 eval $(hexdump -v -s 520 -n 20 -e '1/4 "lzma_compressed_size=%u; " 1/4 "lzma_uncompressed_size=%u; " 1/4 "reed_solomon_redundancy=%u; " 1/4 "reed_solomon_length=%u; boot_dev=" 3/1 "%x" 1 "; boot_drive=%d;"' ${core_img_file});
2119
2120
2121
2122 # Do we have xz or lzma installed?
2123 if [ "${UNLZMA}" != 'none' ] ; then
2124 if [ ${offset_lzma} -ne 0 ] ; then
2125
2126 # Grub2 pads the start of the lzma stream to a 16 bytes boundary.
2127 # Correct the offset to the lzma stream if necessary
2128 # Current GCC adds lea instructions as pad bytes
2129 padsize=$(( (((${offset_lzma} + 15) >> 4) << 4) - ${offset_lzma} ));
2130 if ( [ ${padsize} -gt 0 ] ) ; then
2131 offset_lzma=$(( ${offset_lzma} + ${padsize} ));
2132 fi
2133
2134
2135 # Make lzma header (13 bytes): ${lzma_uncompressed_size} must be displayed in little endian format.
2136 printf '\x5d\x00\x00\x01\x00'$( printf '%08x' ${lzma_uncompressed_size} \
2137 | ${AWK} '{printf "\\x%s\\x%s\\x%s\\x%s", substr($0,7,2), substr($0,5,2), substr($0,3,2), substr($0,1,2)}' )'\x00\x00\x00\x00' > ${Tmp_Log};
2138
2139
2140 # Get lzma_stream, add it after the lzma header and decompress it.
2141 dd if=${core_img_file} bs=${offset_lzma} skip=1 count=${lzma_compressed_size} 2>> ${Trash} \
2142 | cat ${Tmp_Log} - | ${UNLZMA} 2>> ${Trash} > ${core_img_file_unlzma};
2143
2144
2145 # Get offset to the grub_module_info structure in the uncompressed part.
2146 eval $(hexdump -v -s 19 -n 4 -e '1/4 "grub_module_info_offset=%u;"' ${core_img_file_unlzma});
2147
2148 eval $(hexdump -v -n 12 -s ${grub_module_info_offset} -e '"grub_module_magic=" 4/1 "%_c" 1/4 "; grub_modules_offset=%u; " 1/4 "grub_modules_size=%u;"' ${core_img_file_unlzma});
2149
2150 # Check for the existence of the grub_module_magic.
2151 if [ x"${grub_module_magic}" = x'mimg' ] ; then
2152 # Embedded grub modules found.
2153 grub_modules_end_offset=$(( ${grub_module_info_offset} + ${grub_modules_size} ));
2154 grub_module_header_offset=$(( ${grub_module_info_offset} + ${grub_modules_offset} ));
2155
2156 # Traverse through the list of modules and check if it is a config module.
2157 # Upstream GRUB2 supports following module types:
2158 # 0 - ELF modules; may be included multiple times
2159 # 1 - memory disk image; should be included just once
2160 # 2 - embedded initial configuration code; should be included just once
2161 # 3 - initial value of ${prefix} variable. Device part may be omitted,
2162 # in which case device is guessed at startup
2163 # 4 - public GPG keyring used for file signature checking;
2164 # may be included multiple times
2165 #
2166 # All parts are optional (although in practice
2167 # at least drivers for disk and filesystem must be
2168 # present).
2169 #
2170 # Since RPM version 2.00-10 fedora includes patch that
2171 # inserts additional module type after the first one,
2172 # thus shifting all numbers starting with 1. So
2173 # embedded config and prefix become 3 and 4 on fedora.
2174 while [ ${grub_module_header_offset} -lt ${grub_modules_end_offset} ] ; do
2175
2176 if [ $(( ${grub_modules_end_offset} - ${grub_module_header_offset} )) -lt 8 ] ; then
2177 echo 'Remaining space in GRUB2 module list too short for a module' >&2;
2178 all_modules="${all_modules} <short>";
2179 need_core_prologue=1;
2180 break
2181 fi
2182
2183 eval $( hexdump -v -n 8 -s ${grub_module_header_offset} -e '1/4 "grub_module_type=%u; " 1/4 "grub_module_size=%u;"' ${core_img_file_unlzma} );
2184 # Next module is always aligned on 4 bytes boundary on i386,
2185 # but sometimes grub stores shorter size. Make sure to adjust it.
2186 grub_module_header_next=$(( ${grub_module_header_offset} + 8 + (((${grub_module_size} - 8 + 3) >> 2) << 2) ));
2187
2188 if [ ${grub_module_header_next} -gt ${grub_modules_end_offset} ] ; then
2189 printf 'GRUB2 module size too large; skipping remaining modules. Size left: %d\n' $(( {grub_modules_end_offset} - ${grub_module_header_offset} )) >&2;
2190 all_modules="${all_modules} <skipped>";
2191 need_core_prologue=1;
2192 break
2193 fi
2194
2195 if [ ${grub_module_type} -eq 0 ] ; then
2196 # Regular ELF module
2197 dd count=$(( grub_module_size - 8 )) skip=$(( grub_module_header_offset + 8 )) if=${core_img_file_unlzma} of=${GRUB200_Module} bs=1 2>> ${Trash};
2198 modname=$(grub2_modname ${GRUB200_Module} $(( grub_module_size - 8 )));
2199 if [ -n "${modname}" ] ; then
2200 all_modules="${all_modules} ${modname}";
2201 need_core_prologue=1;
2202 fi
2203 elif [ ${grub_module_type} -eq 1 ] ; then
2204 # "stale" ELF module on fedora or memory disk everywhere else
2205 if [ ${core_img_flavour} = 'detect' ] ; then
2206 if [ "$(hexdump -v -n 4 -s $((grub_module_header_offset+8)) -e '"%c"' ${core_img_file_unlzma})" = $'\x7f''ELF' ] ; then
2207 # fedora "stale" ELF module
2208 # TODO display Fedora stale modules
2209 core_img_flavour='fedora';
2210 else
2211 core_img_flavour='upstream';
2212 fi
2213 fi
2214
2215 elif [ ${grub_module_type} -eq 2 ] ; then
2216 # memory disk on fedora or embedded config everywhere else
2217 if [ ${core_img_flavour} = 'detect' ] ; then
2218 # Normally core.img will have prefix which is easier to detect,
2219 # so leave detection as last resort.
2220 dd if=${core_img_file_unlzma} of=${core_img_file_type_2} bs=1 skip=$((grub_module_header_offset+8)) count=$((grub_module_size-8)) 2>> ${Trash};
2221 fi
2222 if [ ${core_img_flavour} = 'upstream' ] ; then
2223 # This module is an embedded config file.
2224 embedded_config_found=1;
2225 need_core_prologue=1;
2226
2227 # Remove padding starting with the first "\0" at the end.
2228 embedded_config=$( hexdump -v -n $(( ${grub_module_size} - 8 )) -s $(( ${grub_module_header_offset} + 8 )) -e '"%_c"' ${core_img_file_unlzma} | sed -e 's/\(\\0\).*$//');
2229 fi
2230
2231 elif [ ${grub_module_type} -eq 3 ] ; then
2232 # embedded config on fedora or prefix everywhere else
2233 if [ ${core_img_flavour} = 'detect' ] ; then
2234 # if it looks like file name, assume prefix
2235 if [[ "$(hexdump -v -n 1 -s $(( grub_module_header_offset + 8 )) -e '"%c"' ${core_img_file_unlzma})" == [/\(] ]] ; then
2236 core_img_flavour='upstream';
2237 else
2238 core_img_flavour='fedora';
2239 fi
2240 fi
2241 if [ ${core_img_flavour} = 'upstream' ] ; then
2242 # This module contains the prefix.
2243
2244 # Get core dir.
2245 # Remove padding "\0"'s at the end.
2246 core_dir=$( hexdump -v -n $(( ${grub_module_size} - 8 )) -s $(( ${grub_module_header_offset} + 8 )) -e '"%_c"' ${core_img_file_unlzma} | sed -e 's/\(\\0\)\+$//');
2247 elif [ ${core_img_flavour} = 'fedora' ] ; then
2248 # This module is an embedded config file.
2249 embedded_config_found=1;
2250 need_core_prologue=1;
2251
2252 # Remove padding starting with the first "\0" at the end.
2253 embedded_config=$( hexdump -v -n $(( ${grub_module_size} - 8 )) -s $(( ${grub_module_header_offset} + 8 )) -e '"%_c"' ${core_img_file_unlzma} | sed -e 's/\(\\0\).*$//');
2254 fi
2255
2256 elif [ ${grub_module_type} -eq 4 ] ; then
2257 # prefix on fedora or GPG keyring everywhere else
2258 if [ ${core_img_flavour} = 'detect' ] ; then
2259 # if it looks like file name, assume prefix
2260 # GPG ring normall has \x99 as first byte
2261 if [[ "$(hexdump -v -n 1 -s $(( grub_module_header_offset + 8 )) -e '"%c"' ${core_img_file_unlzma})" == [/\(] ]] ; then
2262 core_img_flavour='fedora';
2263 else
2264 core_img_flavour='upstream';
2265 fi
2266 fi
2267 if [ ${core_img_flavour} = 'fedora' ] ; then
2268 # This module contains the prefix.
2269
2270 # Get core dir.
2271 # Remove padding "\0"'s at the end.
2272 core_dir=$( hexdump -v -n $(( ${grub_module_size} - 8 )) -s $(( ${grub_module_header_offset} + 8 )) -e '"%_c"' ${core_img_file_unlzma} | sed -e 's/\(\\0\)\+$//');
2273 elif [ ${core_img_flavour} = 'upstream' ] ; then
2274 # TODO list GPG keyring
2275 :
2276 fi
2277 fi
2278
2279 grub_module_header_offset=${grub_module_header_next};
2280
2281 done
2282 fi
2283 fi
2284 else
2285 # When xz or lzma isn't available, we can't get the core_dir, but we still can show some info.
2286 core_dir='??';
2287
2288 echo 'To be able to see for which directory Grub2 (v2.00) looks for, install "xz" or "lzma".' >&2;
2289 fi
2290 fi
2291 fi
2292 fi
2293 fi
2294 done
2295
2296 if [ "${grub2_version}" = '2.00' ] ; then
2297 if [ -s ${core_img_file_type_2} ] ; then
2298 if [ "${core_img_flavour}" = 'detect' ] ; then
2299 # Neither type 1, 3 or 4 modules were present. So we have either
2300 # embedded config or memory disk.
2301 if type file > /dev/null 2>&1 ; then
2302 if [[ "$(LC_ALL=C file ${core_img_file_type_2})" == *"ASCII text"* ]] ; then
2303 # upstream embedded config
2304 core_img_flavour='upstream';
2305 fi
2306 fi
2307 fi
2308 if [ ${core_img_flavour} = 'upstream' ] ; then
2309 embedded_config_found=1;
2310 need_core_prologue=1;
2311
2312 # Remove padding starting with the first "\0" at the end.
2313 embedded_config=$( hexdump -v -e '"%_c"' ${core_img_file_type_2} | sed -e 's/\(\\0\).*$//' );
2314 fi
2315 fi
2316 fi
2317
2318
2319 if [ ${core_img_found} -eq 0 ] ; then
2320 # core.img not found.
2321 Grub2_Msg="${Grub2_Msg}, but core.img can not be found at this location";
2322 else
2323 # core.img found.
2324
2325 Grub2_Msg="${Grub2_Msg}. core.img is at this location";
2326
2327 # In GRUB 2.00 core.img prefix is optional
2328 if [ -n "${core_dir}" ]; then
2329 Grub2_Msg="${Grub2_Msg} and looks for ${core_dir}";
2330
2331 if [ -n "${partition}" ]; then
2332 partition=$(( ${partition} + 1 ));
2333 if [ ${partition} -eq 255 ] ; then
2334 Grub2_Msg="${Grub2_Msg} on this drive";
2335 else
2336 Grub2_Msg="${Grub2_Msg} in partition ${partition}";
2337 fi
2338 fi
2339 fi
2340
2341 if [ ${need_core_prologue} -eq 1 ] ; then
2342 Grub2_Msg=$(printf "${Grub2_Msg}. It also embeds following components:");
2343 fi
2344
2345 if [ -n "${all_modules}" ] ; then
2346
2347 all_modules="${all_modules# }";
2348 Grub2_Msg=$(printf "${Grub2_Msg}\n\nmodules\n--------------------------------------------------------------------------------\n${all_modules}\n--------------------------------------------------------------------------------");
2349
2350 fi
2351
2352 if [ ${embedded_config_found} -eq 1 ] ; then
2353 # Embedded config file found.
2354
2355 Grub2_Msg=$(printf "${Grub2_Msg}\n\nconfig script\n--------------------------------------------------------------------------------\n${embedded_config}\n--------------------------------------------------------------------------------");
2356
2357 fi
2358 fi
2359}
2360
2361
2362
2363## Get embedded menu for grub4dos (grldr/grub.exe) and wee (installed in the MBR). ##
2364#
2365# Function arguments:
2366#
2367# - arg 1: source = file (grub4dos) / device (WEE)
2368# - arg 2: titlename = first part of the title that needs to be displayed
2369#
2370
2371get_embedded_menu () {
2372 local source=$1 titlename=$2;
2373
2374 # Check if magic bytes that go before the embedded menu, are present.
2375 offset_menu=$(dd if="${source}" count=4 bs=128k 2>> ${Trash} | hexdump -v -e '/1 "%02x"' | grep -b -o 'b0021ace000000000000000000000000');
2376
2377 if [ -n "${offset_menu}" ] ; then
2378 # Magic found.
2379 titlebar_gen "${titlename}" " embedded menu";
2380 echo '--------------------------------------------------------------------------------' >> "${Log1}";
2381
2382 # Calcutate the exact offset to the embedded menu.
2383 offset_menu=$(( ( ${offset_menu%:*} / 2 ) + 16 ));
2384 dd if="${source}" count=1 skip=1 bs=${offset_menu} 2>> ${Trash} | ${AWK} 'BEGIN { RS="\0" } { if (NR == 1) print $0 }' >> "${Log1}";
2385
2386 echo '--------------------------------------------------------------------------------' >> "${Log1}";
2387 fi
2388}
2389
2390
2391
2392## Show the location (offset) of a file on a disk ##
2393#
2394# Function arguments:
2395#
2396# - arg 1: filename1
2397# - arg 2: filename2
2398# - arg 3: filename3
2399# - ......
2400#
2401# Return values:
2402#
2403# - 0: None of the provided filenames was found.
2404# - 1: At least one of the provided filenames was found.
2405
2406last_block_of_file () {
2407 local display='0';
2408 local BlockSize Fragments Filefrag_Format EndGiByte EndGByte;
2409
2410 # Remove an existing ${Tmp_Log} log.
2411 rm -f ${Tmp_Log};
2412
2413 # "$@" contains all function arguments (filenames).
2414 for file in "$@" ; do
2415 if [[ -f "${file}" ]] && [[ -s "${file}" ]] && FileNotMounted "${mountname}/${file}" "${mountname}" ; then
2416
2417 # There are 4 versions of e2fsprogs filefrag output.
2418 # In all cases final line could be "1 extent" instead.
2419 #
2420 # v1
2421 # Blocksize of file %s is %d
2422 # File size of %s is %lld (%d blocks)
2423 # %s: %d extents found[, perfection would be %d extent%s]
2424 #
2425 # v2
2426 # Blocksize of file %s is %d
2427 # File size of %s is %lld (%d blocks)
2428 # First block: %ld
2429 # Last block: %ld
2430 # %s: %d extents found[, perfection would be %d extent%s]
2431 #
2432 # v3
2433 # File size of %s is %lld (%ld block%s, blocksize %d)
2434 # ext logical physical expected length flags
2435 # 0 nnn nnn nnn xxx
2436 # 1 nnn nnn nnn nnn xxx
2437 # ...
2438 # %s: %d extents found[, perfection would be %d extent%s]
2439 #
2440 # v4
2441 # File size of %s is %llu (%lu block%s of %d bytes)
2442 # ext: logical_offset: physical_offset: length: expected: flags:
2443 # 0: nnn.. nnn: nnn.. nnn: nnn: xxx
2444 # 1: nnn.. nnn: nnn.. nnn: nnn: nnn: xxx
2445 # ...
2446 # %s: %d extents found[, perfection would be %d extent%s]
2447 #
2448 # FIXME e2fsprogs filefrag output "Last block:", not "Last Block:".
2449 # Was there yet another filefrag implementation?
2450 #
2451 # XXX Original code metioned filefrag output that can show last
2452 # block but not number of extents. Unless there was some other
2453 # implementation of filefrag, it does not match e2fsprogs sources.
2454 #
2455 # XXX Can we hit files with spaces (field count is wrong then)?
2456
2457 eval $(filefrag -v "${file}" \
2458 | ${AWK} -F ' ' 'BEGIN { blocksize=0; expected=0; extents=0; ext_ind=0; last_ext_loc=0; ext_length=0; filefrag_format=""; last_block=0 } \
2459 { if ( $1 == "Blocksize" ) { blocksize=$6; filefrag_format="v1"; }; \
2460 if ( filefrag_format == "v1" ) { \
2461 if ( $1$2 ~ "LastBlock:" ) { last_block = $3 }; \
2462 } else if ( $(NF-1) == "blocksize" ) { \
2463 blocksize = substr($NF,0,length($NF) - 1); \
2464 filefrag_format = "v3"; \
2465 } else if ( $(NF) == "bytes)" ) { \
2466 blocksize = $(NF-1); \
2467 filefrag_format = "v4"; \
2468 FS=" *|: *|[.][.] *"; \
2469 } \
2470 if ( expected != 0 ) { \
2471 if ( filefrag_format == "v3" && ext_ind == $1 ) { \
2472 if ( last_ext_loc < $3 ) { \
2473 last_ext_loc = $3; \
2474 if ( substr($0, expected, 1) == " " ) { \
2475 ext_length = $4; } \
2476 else { \
2477 ext_length = $5; \
2478 } \
2479 } \
2480 } else if ( filefrag_format == "v4" && ext_ind == $2 ) { \
2481 if ( last_block < $6 ) { \
2482 last_block = $6; \
2483 } \
2484 } \
2485 ext_ind += 1; \
2486 } else { \
2487 if ( filefrag_format == "v3" && $4 == "expected" ) { \
2488 expected= index($0,"expected") + 7; \
2489 } else if ( filefrag_format == "v4" && $2 == "ext" ) { \
2490 expected = 1; \
2491 } \
2492 } \
2493 if ( $3 == "extents" ) { \
2494 extents = $2; \
2495 } else if ( $3 == "extent" ) { \
2496 extents = 1; \
2497 } \
2498 } \
2499 END { \
2500 if ( filefrag_format == "v3" ) { \
2501 last_block = last_ext_loc + ext_length; \
2502 } \
2503 printf "BlockSize=" blocksize "; Fragments=" extents "; Filefrag_Format=" filefrag_format "; "; \
2504 if ( last_block == 0 ) { \
2505 printf "EndGiByte=??; EndGByte=??;" \
2506 } else { \
2507 EndByte = last_block * blocksize + 512 * '${start}'; \
2508 printf "EndGiByte=%.9f; EndGByte=%.9f;", EndByte / 1024 ^ 3, EndByte / 1000 ^ 3; \
2509 } \
2510 }');
2511
2512 if [ "${Filefrag_Format}" = '' ] ; then
2513 echo "Unknown filefrag output format" >&2;
2514 return 0;
2515 fi
2516
2517 if [ "${BlockSize}" -ne 0 ] ; then
2518 if [ "${Fragments}" -eq 0 ] ; then
2519 printf "%14s = %-14s %s\n" "${EndGiByte}" "${EndGByte}" "${file}" >> ${Tmp_Log};
2520 else
2521 printf "%14s = %-14s %-45s %2s\n" "${EndGiByte}" "${EndGByte}" "${file}" "${Fragments}" >> ${Tmp_Log};
2522 fi
2523 fi
2524
2525 # Return 1, when we find at least one of the provided filenames,
2526 # so we know that we need to display the content of ${Tmp_Log} later.
2527 display=1;
2528 fi
2529 done
2530
2531 return ${display};
2532}
2533
2534
2535
2536## Get_Partition_Info search a partition for information relevant for booting. ##
2537#
2538# Function arguments:
2539#
2540# - arg 1: log = local version of RESULT.txt
2541# - arg 2: log1 = local version of log1
2542# - arg 3: part = device for the partition
2543# - arg 4: name = descriptive name for the partition
2544# - arg 5: mountname = path where partition will be mounted.
2545# - arg 6: kind = kind of the partition
2546# - arg 7: start = starting sector of the partition
2547# - arg 8: end = ending sector of the partition
2548# - arg 9: system = system of the partition
2549# - arg 10: PI = PI of the partition, (equal to "", if not a regular partition)
2550
2551Get_Partition_Info() {
2552 local Log="$1" Log1="$2" part="$3" name="$4" mountname="$5" kind="$6" start="$7" end="$8" system="$9" PI="${10}";
2553 local line size=$((end-start)) BST='' BSI='' BFI='' OS='' BootFiles='' Bytes80_to_83='' Bytes80_to_81='' offset='';
2554 local offset_menu='' part_no_mount=0 com32='' com32_version='';
2555
2556
2557 echo "Searching ${name} for information... ";
2558 PrintBlkid ${part};
2559
2560 # Type of filesystem according to blkid.
2561 type=$(BlkidTag ${part} TYPE);
2562
2563 [ "${system}" = 'BIOS Boot partition' ] && type='BIOS Boot partition';
2564 [ -n ${PI} ] && FileArray[${PI}]=${type};
2565
2566 # Display partition subtitle of 80 characters width.
2567 line='________________________________________________________________________________';
2568 line=${line:$(( ${#name} + 2 ))};
2569
2570 printf '%s: %s\n\n' "${name}" "${line}" >> "${Log}";
2571
2572 # Directory where the partition will be mounted.
2573 mkdir -p "${mountname}";
2574
2575 # Check for extended partion.
2576 if ( [ "${kind}" = 'E' ] && [ x"${type}" = x'' ] ) ; then
2577 type='Extended Partition';
2578
2579 # Don't display the error message from blkid for extended partition.
2580 cat ${Tmp_Log} >> ${Trash};
2581 else
2582 cat ${Tmp_Log} >&2;
2583 fi
2584
2585 # Display the File System Type.
2586 echo " File system: ${type}" >> "${Log}";
2587
2588 # Get bytes 0x80-0x83 of the Volume Boot Record (VBR).
2589 Bytes80_to_83=$(hexdump -v -n 4 -s $((0x80)) -e '4/1 "%02x"' ${part});
2590
2591 # Get bytes 0x80-0x81 of the Volume Boot Record (VBR).
2592 Bytes80_to_81="${Bytes80_to_83:0:4}";
2593
2594
2595 case ${Bytes80_to_81} in
2596 0069) BST='ISOhybrid (Syslinux 3.72-3.73)';;
2597 010f) BST='HP Recovery';;
2598 019d) BST='BSD4.4: FAT32';;
2599 0211) BST='Dell Utility: FAT16';;
2600 0488) BST="Grub2's core.img";;
2601 0689) BST='Syslinux 3.00-3.52';
2602 syslinux_info ${part};
2603 BSI="${BSI} ${Syslinux_Msg}";;
2604 0734) BST='Dos_1.0';;
2605 0745) BST='Windows Vista: FAT32';;
2606 089e) BST='MSDOS5.0: FAT16';;
2607 08cd) BST='Windows 2000/XP: NTFS';;
2608 0b60) BST='Dell Utility: FAT16';;
2609 0bd0) BST='MSWIN4.1: FAT32';;
2610 0e00) BST='Dell Utility: FAT16';;
2611 0fb6) BST='ISOhybrid with partition support (Syslinux 3.82-3.86)';;
2612 2a00) BST='ReactOS';;
2613 2d5e) BST='Dos 1.1';;
2614 31c0) BST='Syslinux 4.03 or higher';
2615 syslinux_info ${part} '4.03';
2616 BSI="${BSI} ${Syslinux_Msg}";;
2617 31d2) BST="Grub2's core.img";;
2618 3a5e) BST='Recovery: FAT32';;
2619 407c) BST='ISOhybrid (Syslinux 3.82-4.04)';;
2620 4216) BST='Grub4Dos: NTFS';;
2621 4445) BST='Dell Restore: FAT32';;
2622 55aa) case ${Bytes80_to_83} in
2623 55aa750a) BST='Grub4Dos: FAT32';;
2624 55aa7506) # Get bytes 0x110-0x111 of the Volume Boot Record (VBR).
2625 Bytes110_to_111=$(hexdump -v -n 2 -s $((0x110)) -e '2/1 "%02x"' ${part});
2626 case "${Bytes110_to_111}" in
2627 9090) BST='Windows Vista: NTFS';;
2628 2810) BST='Windows 7/2008: NTFS';;
2629 0a13) BST='Windows 8/2012: NTFS';;
2630 esac;;
2631 esac;;
2632 55cd) BST='FAT32';;
2633 5626) BST='Grub4Dos: EXT2/3/4';;
2634 638b) BST='Freedos: FAT32';;
2635 6616) BST='Windows 7/2008: FAT16';;
2636 696e) BST='FAT16';;
2637 6974) BST='BootIt: FAT16';;
2638 6f65) BST='BootIt: FAT16';;
2639 6f6e) BST='-';; # 'MSWIN4.1: Fat 32'
2640 6f74) BST='FAT32';;
2641 7405) BST='Windows 7/2008: FAT32';;
2642 7815) case ${Bytes80_to_83} in
2643 7815b106) BST='Syslinux 3.53-3.86';
2644 syslinux_info ${part};
2645 BSI="${BSI} ${Syslinux_Msg}";;
2646 7815* ) BST='FAT32';;
2647 esac;;
2648 7cc6) BST='MSWIN4.1: FAT32';;
2649 # 7cc6) BST='Win_98';;
2650 7e1e) BST='Grub4Dos: FAT12/16';;
2651 8a56) BST='Acronis SZ: FAT32';;
2652 83e1) BST='ISOhybrid with partition support (Syslinux 4.00-4.04)';;
2653 8ec0) BST='Windows XP: NTFS';;
2654 8ed0) BST='Dell Recovery: FAT32';;
2655 b106) BST='Syslinux 4.00-4.02';
2656 syslinux_info ${part};
2657 BSI="${BSI} ${Syslinux_Msg}";;
2658 b600) BST='Dell Utility: FAT16';;
2659 b6c6) BST='ISOhybrid with partition support (Syslinux 3.81)';;
2660 b6d1) BST='Windows XP: FAT32';;
2661 e2f7) BST='FAT32, Non Bootable';;
2662 e879) BST='ISOhybrid (Syslinux 3.74-3.80)';;
2663 e9d8) BST='Windows Vista/7: NTFS';;
2664 f6c1) BST='Windows 8/2012: FAT32';;
2665 f6f6) BST='- (cleared BS by FDISK)';;
2666 fa33) BST='Windows XP: NTFS';;
2667 fbc0) BST='ISOhybrid (Syslinux 3.81)';;
2668
2669 ## If Grub or Grub 2 is in the boot sector, investigate the embedded information. ##
2670 48b4) BST='Grub2 (v1.96)';
2671 grub2_info ${part} ${drive} '1.96' 'partition';
2672 BSI="${BSI} Grub2 (v1.96) is installed in the boot sector of ${name} and ${Grub2_Msg}.";;
2673 7c3c) BST='Grub2 (v1.97-1.98)';
2674 grub2_info ${part} ${drive} '1.97-1.98' 'partition';
2675 BSI="${BSI} Grub2 (v1.97-1.98) is installed in the boot sector of ${name} and ${Grub2_Msg}.";;
2676 0020) BST='Grub2 (v1.99-2.00)';
2677 grub2_info ${part} ${drive} '1.99-2.00' 'partition';
2678 BSI="${BSI} Grub2 (v${grub2_version}) is installed in the boot sector of ${name} and ${Grub2_Msg}.";;
2679 aa75 | 5272) BST='Grub Legacy';
2680 stage2_loc ${part};
2681 BSI="${BSI} Grub Legacy (v${Grub_Version}) is installed in the boot sector of ${name} and ${Stage2_Msg}";;
2682
2683 ## If Lilo is in the VBR, look for map file ##
2684 8053) BST='LILO';
2685 # 0x20-0x23 contains the offset of /boot/map.
2686 offset=$(hexdump -v -s 32 -n 4 -e '"%u"' ${part});
2687
2688 BSI="${BSI} LILO is installed in boot sector of ${part} and looks at sector ${offset} of ${drive} for the \"map\" file,";
2689
2690 # check whether offset is on the hard drive.
2691 if [ ${offset} -lt ${size} ] ; then
2692 tmp=$(dd if=${drive} skip=${offset} count=1 2>> ${Trash} | hexdump -v -s 508 -n 4 -e '"%_p"');
2693
2694 if [ "${tmp}" = 'LILO' ] ; then
2695 BSI="${BSI} and the \"map\" file was found at this location.";
2696 else
2697 BSI="${BSI} but the \"map\" file was not found at this location.";
2698 fi
2699 else
2700 BSI="${BSI} but the \"map\" file was not found at this location.";
2701 fi;;
2702
2703 0000) # If the first two bytes are zero, the boot sector does not contain any boot loader.
2704 BST='-';;
2705
2706 esac
2707
2708 if [ x"${BST}" = 'x' ] ; then
2709 BST='Unknown';
2710 printf "Unknown BootLoader on ${name}\n\n" >> ${Unknown_MBR};
2711 hexdump -n 512 -C ${part} >> ${Unknown_MBR};
2712 echo >> ${Unknown_MBR};
2713 fi
2714
2715 # Display the boot sector type.
2716 echo " Boot sector type: ${BST}" >> "${Log}";
2717
2718
2719
2720 ## Investigate the Boot Parameter Block (BPB) of a NTFS partition. ##
2721
2722 if [ "${type}" = 'ntfs' ] ; then
2723 offset=$(hexdump -v -s 28 -n 4 -e '"%u"' ${part});
2724 BPB_Part_Size=$(hexdump -v -s 40 -n 4 -e '"%u"' ${part})
2725 Comp_Size=$(( (${BPB_Part_Size} - ${size}) / 256 ))
2726 SectorsPerCluster=$(hexdump -v -s 13 -n 1 -e '"%d"' ${part});
2727 MFT_Cluster=$(hexdump -v -s 48 -n 4 -e '"%d"' ${part});
2728 MFT_Sector=$(( ${MFT_Cluster} * ${SectorsPerCluster} ));
2729
2730 # Track=$(hexdump -v -s 24 -n 2 -e '"%u"' ${part})'' # Number of sectors per track.
2731 # Heads=$(hexdump -v -s 26 -n 2 -e '"%u"' ${part})'' # Number of heads.
2732 #
2733 # if [ "${Heads}" -ne 255 ] || [ "${Track}" -ne 63 ] ; then
2734 # BSI="${BSI} Geometry: ${Heads} Heads and ${Track} sectors per Track."
2735 # fi
2736
2737 if [[ "${MFT_Sector}" -lt "${size}" ]] ; then
2738 MFT_FILE=$(dd if=${part} skip=${MFT_Sector} count=1 2>> ${Trash} | hexdump -v -n 4 -e '"%_u"');
2739 else
2740 MFT_FILE='';
2741 fi
2742
2743 MFT_Mirr_Cluster=$(hexdump -v -s 56 -n 4 -e '"%d"' ${part});
2744 MFT_Mirr_Sector=$(( ${MFT_Mirr_Cluster} * ${SectorsPerCluster} ));
2745
2746 if [[ "${MFT_Mirr_Sector}" -lt "${size}" ]] ; then
2747 MFT_Mirr_FILE=$(dd if=${part} skip=${MFT_Mirr_Sector} count=1 2>> ${Trash} | hexdump -v -n 4 -e '"%_u"');
2748 else
2749 MFT_Mirr_FILE='';
2750 fi
2751
2752 if ( [ "${offset}" -eq "${start}" ] && [ "${MFT_FILE}" = 'FILE' ] && [ "${MFT_Mirr_FILE}" = 'FILE' ] && [ "${Comp_Size}" -eq 0 ] ) ; then
2753 BSI="${BSI} No errors found in the Boot Parameter Block.";
2754 else
2755 if [[ "${offset}" -ne "${start}" ]] ; then
2756 BSI="${BSI} According to the info in the boot sector, ${name} starts at sector ${offset}.";
2757
2758 if [[ "${offset}" -ne 63 && "${offset}" -ne 2048 && "${offset}" -ne 0 || "${kind}" != 'L' ]] ; then
2759 BSI="${BSI} But according to the info from fdisk, ${name} starts at sector ${start}.";
2760 fi
2761 fi
2762
2763 if [[ "${MFT_FILE}" != "FILE" ]] ; then
2764 BSI="${BSI} The info in boot sector on the starting sector of the MFT is wrong.";
2765 printf "MFT Sector of ${name}\n\n" >> ${Unknown_MBR};
2766 dd if=${part} skip=${MFT_Sector} count=1 2>> ${Trash} | hexdump -C >> ${Unknown_MBR};
2767 fi
2768
2769 if [[ "${MFT_Mirr_FILE}" != 'FILE' ]] ; then
2770 BSI="${BSI} The info in the boot sector on the starting sector of the MFT Mirror is wrong.";
2771 fi
2772
2773 if [[ "${Comp_Size}" -ne 0 ]] ; then
2774 BSI="${BSI} According to the info in the boot sector, ${name} has ${BPB_Part_Size} sectors, but according to the info from fdisk, it has ${size} sectors.";
2775 fi
2776 fi
2777 fi
2778
2779
2780
2781 ## Investigate the Boot Parameter Block (BPB) of (some) FAT partition. ##
2782
2783 # Identifies Fat Bootsectors which are used for booting.
2784 # if [[ "${Bytes80_to_81}" = '7cc6' || "${Bytes80_to_81}" = '7815' || "${Bytes80_to_81}" = 'b6d1' || "${Bytes80_to_81}" = '7405' || "${Bytes80_to_81}" = '6974' || "${Bytes80_to_81}" = '0bd0' || "${Bytes80_to_81}" = '089e' ]] ;
2785
2786 if [[ "${type}" = 'vfat' ]] ; then
2787 offset=$(hexdump -v -s 28 -n 4 -e '"%d\n"' ${part}); # Starting sector the partition according to BPB.
2788 BPB_Part_Size=$(hexdump -v -s 32 -n 4 -e '"%d"' ${part}); # Partition size in sectors according to BPB.
2789 Comp_Size=$(( (BPB_Part_Size - size)/256 )) # This number will be unequal to zero, if the 2
2790 # partions sizes differ by more than 255 sectors.
2791
2792 #Track=$(hexdump -v -s 24 -n 2 -e '"%u"' ${part})'' # Number of sectors per track.
2793 #Heads=$(hexdump -v -s 26 -n 2 -e '"%u"' ${part})'' # Number of heads
2794 #if [[ "${Heads}" -ne 255 || "${Track}" -ne 63 ]] ; then # Checks for an usual geometry.
2795 # BSI=$(echo ${BSI}" "Geometry: ${Heads} Heads and ${Track} sectors per Track.) ### Report unusal geometry
2796 #fi;
2797
2798 # Check whether Partitons starting sector and the Partition Size of BPB and fdisk agree.
2799 if [[ "${offset}" -eq "${start}" && "${Comp_Size}" -eq "0" ]] ; then
2800 BSI="${BSI} No errors found in the Boot Parameter Block."; # If they agree.
2801 else # If they don't agree.
2802 if [[ "${offset}" -ne "${start}" ]] ; then # If partition starting sector disagrees.
2803 # Display the starting sector according to the BPB.
2804 BSI="${BSI} According to the info in the boot sector, ${name} starts at sector ${offset}.";
2805
2806 # Check whether partition is a logcial partition and if its starting sector value is a 63 or 2048.
2807 if [[ "${offset}" -ne "63" && "${offset}" -ne "2048" || "${kind}" != "L" ]] ; then
2808 # If not, display starting sector according to fdisk.
2809 BSI="${BSI} But according to the info from fdisk, ${name} starts at sector ${start}.";
2810 else
2811 # This is quite common occurence, and only matters if one tries to boot Windows from a logical partition.
2812 BSI="${BSI} But according to the info from fdisk, ${name} starts at sector ${start}. \"63\" and \"2048\" are quite common values for the starting sector of a logical partition and they only need to be fixed when you want to boot Windows from a logical partition.";
2813 fi
2814 fi
2815
2816 # If partition sizes from BPB and FDISK differ by more than 255 sector, display both sizes.
2817 if [[ "${Comp_Size}" -ne "0" ]] ; then
2818 BSI="${BSI} According to the info in the boot sector, ${name} has ${BPB_Part_Size} sectors.";
2819
2820 if [[ "$BPB_Part_Size" -ne 0 ]] ; then
2821 BSI="${BSI}. But according to the info from the partition table, it has ${size} sectors.";
2822 fi # Don't display a warning message in the common case BPB_Part_Size=0.
2823 fi
2824 fi # End of BPB Error if-then-else.
2825 fi # End of Investigation of the BPB of vfat partitions.
2826
2827
2828
2829 ## Display boot sector info. ##
2830
2831 printf ' Boot sector info: ' >> "${Log}";
2832 printf "${BSI}\n" | fold -s -w 55 | sed -e '/^-------------------------\.\?$/ d' -e '2~1s/.*/ &/' >> "${Log}";
2833
2834
2835
2836
2837 ## Exclude partitions which contain no information, or which we (currently) don't know how to accces. ##
2838
2839 case "${type}" in
2840 'BIOS Boot partition' ) part_no_mount=1;;
2841 'crypto_LUKS' ) part_no_mount=1;;
2842 'Extended Partition' ) part_no_mount=1;;
2843 'linux_raid_member' ) part_no_mount=1;;
2844 'LVM2_member' ) part_no_mount=1;;
2845 'swap' ) part_no_mount=1;;
2846 'unknown volume type' ) part_no_mount=1;;
2847 'zfs_member' ) part_no_mount=1;;
2848 '' ) part_no_mount=1;;
2849 esac
2850
2851 if [ "${part_no_mount}" -eq 0 ] ; then
2852
2853 # Look for a mount point of the current partition.
2854 # If multiple mount points are found, use the one with the shortest pathname.
2855 CheckMount=$(mount | ${AWK} -F "\t" '$0 ~ "^'${part}' " { sub(" on ", "\t", $0); sub(" type ", "\t", $0); print $2 }' | sort | ${AWK} '{ print $0; exit}');
2856
2857 # Check whether partition is already mounted.
2858 if [ x"${CheckMount}" != x'' ] ; then
2859 if [ "${CheckMount}" = "/" ] ; then
2860 mountname='';
2861 else
2862 # If yes, use the existing mount point.
2863 mountname="${CheckMount}";
2864 fi
2865 fi
2866
2867 # Clear mount errors for previous partition
2868 > ${Mount_Error}
2869
2870 # Try to mount the partition.
2871 if [ x"${CheckMount}" != x'' ] || mount -r -t "${type}" ${part} "${mountname}" 2>> ${Mount_Error} \
2872 || ( [ "${type}" = ntfs ] && ntfs-3g -o ro ${part} "${mountname}" 2>> ${Mount_Error} ) ; then
2873
2874 # If partition is mounted, try to identify the Operating System (OS) by looking for files specific to the OS.
2875 OS='';
2876
2877 grep -q "W.i.n.d.o.w.s. .V.i.s.t.a" "${mountname}"/{windows,Windows,WINDOWS}/{System32,system32}/{Winload,winload}.exe 2>> ${Trash} && OS='Windows Vista';
2878
2879 grep -q "W.i.n.d.o.w.s. .7" "${mountname}"/{windows,Windows,WINDOWS}/{System32,system32}/{Winload,winload}.exe 2>> ${Trash} && OS='Windows 7';
2880
2881 grep -q "w.i.n.8._." "${mountname}"/{windows,Windows,WINDOWS}/{System32,system32}/{Winload,winload}.exe 2>> ${Trash} && OS='Windows 8';
2882
2883 for WinOS in 'MS-DOS' 'MS-DOS 6.22' 'MS-DOS 6.21' 'MS-DOS 6.0' 'MS-DOS 5.0' 'MS-DOS 4.01' 'MS-DOS 3.3' 'Windows 98' 'Windows 95'; do
2884 grep -q "${WinOS}" "${mountname}"/{IO.SYS,io.sys} 2>> ${Trash} && OS="${WinOS}";
2885 done
2886
2887 [ -s "${mountname}/Windows/System32/config/SecEvent.Evt" ] || [ -s "${mountname}/WINDOWS/system32/config/SecEvent.Evt" ] || [ -s "${mountname}/WINDOWS/system32/config/secevent.evt" ] || [ -s "${mountname}/windows/system32/config/secevent.evt" ] && OS='Windows XP';
2888
2889 [ -s "${mountname}/ReactOS/system32/config/SecEvent.Evt" ] && OS='ReactOS';
2890
2891 [ -s "${mountname}/etc/issue" ] && OS=$(sed -e 's/\\. //g' -e 's/\\.//g' -e 's/^[ \t]*//' "${mountname}"/etc/issue);
2892
2893 [ -s "${mountname}/etc/slackware-version" ] && OS=$(sed -e 's/\\. //g' -e 's/\\.//g' -e 's/^[ \t]*//' "${mountname}"/etc/slackware-version);
2894
2895 [ -s "${mountname}/etc/redhat-release" ] && OS=$(cat "${mountname}"/etc/redhat-release | tr -d '\n');
2896
2897 [ -s "${mountname}/etc/os-release" ] && grep -q '^PRETTY_NAME=' "${mountname}/etc/os-release" && OS=$(eval "$(grep '^PRETTY_NAME=' "${mountname}"/etc/os-release)"; printf '%s' "${PRETTY_NAME}" | tr -d '\n');
2898
2899
2900 ## Search for the files in ${Bootfiles} ##
2901 #
2902 # If found, display their content.
2903
2904 BootFiles='';
2905
2906 if [ "${type}" = 'vfat' ] ; then
2907 Boot_Files=${Boot_Files_Fat};
2908 else
2909 Boot_Files=${Boot_Files_Normal};
2910 fi
2911
2912 for file in ${Boot_Files} ; do
2913 if [ -f "${mountname}${file}" ] && [ -s "${mountname}${file}" ] && FileNotMounted "${mountname}${file}" "${mountname}" ; then
2914 BootFiles="${BootFiles} ${file}";
2915
2916 # Check whether the file is a symlink.
2917 if ! [ -h "${mountname}${file}" ] ; then
2918 # if not a symlink, display content.
2919
2920 if ( [ ${file} = '/grldr' ] || [ ${file} = '/grub.exe' ] ) ; then
2921 # Display the embedded menu of grub4dos.
2922 get_embedded_menu "${mountname}${file}" "${name}${file}";
2923 else
2924 titlebar_gen "${name}" ${file}; # Generates a titlebar above each file listed.
2925 echo '--------------------------------------------------------------------------------' >> "${Log1}";
2926 cat "${mountname}${file}" >> "${Log1}";
2927 echo '--------------------------------------------------------------------------------' >> "${Log1}";
2928 fi
2929 fi
2930 fi
2931 done
2932
2933
2934
2935 ## Search for Wubi partitions. ##
2936
2937 if [ -f "${mountname}/ubuntu/disks/root.disk" ] ; then
2938 Wubi=$(losetup -a | ${AWK} '$3 ~ "(/host/ubuntu/disks/root.disk)" { print $1; exit }' | sed 's/.$//' );
2939
2940 # check whether Wubi already has a loop device.
2941 if [[ x"${Wubi}" = x'' ]] ; then
2942 Wubi=$(losetup -f --show "${mountname}/ubuntu/disks/root.disk" );
2943 WubiDev=0;
2944 else
2945 WubiDev=1;
2946 fi
2947
2948 if [ x"${Wubi}" != x'' ] ; then
2949 Get_Partition_Info "${Log}"x "${Log1}"x "${Wubi}" "${name}/Wubi" "Wubi/${mountname}" 'Wubi' 0 0 'Wubi' '';
2950
2951 # Remove Wubu loop device, if created by BIS.
2952 [[ ${WubiDev} -eq 0 ]] && losetup -d "${Wubi}";
2953 else
2954 echo "Found Wubi on ${name}. But could not create a loop device." >&2;
2955 fi
2956 fi
2957
2958
2959
2960 ## Search for the filenames in ${Boot_Prog}. ##
2961 #
2962 # If found displays their names.
2963
2964 if [ "${type}" = 'vfat' ] ; then
2965 # Check FAT filesystems for EFI boot files.
2966 for file in "${mountname}"/efi/{,*/}*/*.efi; do
2967 # Remove "${mountname}" part of the filename.
2968 file="${file#${mountname}}";
2969
2970 if [ -f "${mountname}${file}" ] && [ -s "${mountname}${file}" ] && FileNotMounted "${mountname}${file}" "${mountname}" ; then
2971 BootFiles="${BootFiles} ${file}";
2972 fi
2973 done
2974
2975 # Other boot program files.
2976 Boot_Prog=${Boot_Prog_Fat};
2977 else
2978 Boot_Prog=${Boot_Prog_Normal};
2979 fi
2980
2981 for file in ${Boot_Prog} ; do
2982 if [ -f "${mountname}${file}" ] && [ -s "${mountname}${file}" ] && FileNotMounted "${mountname}${file}" "${mountname}" ; then
2983 BootFiles="${BootFiles} ${file}";
2984 fi
2985 done
2986
2987
2988
2989 ## Search for files containing boot codes. ##
2990
2991 # Loop through all directories which might contain boot_code files.
2992 for file in ${Boot_Codes_Dir} ; do
2993
2994 # If such directory exist ...
2995 if [ -d "${mountname}${file}" ] && FileNotMounted "${mountname}${file}" "${mountname}" ; then
2996 # Look at the content of that directory.
2997 for loader in $( ls "${mountname}${file}" ) ; do
2998 # If it is a file ...
2999 if [ -f "${mountname}${file}${loader}" ] && [ -s "${mountname}${file}${loader}" ] ; then
3000
3001 # Bootpart code has "BootPart" written at 0x101
3002 sig=$(hexdump -v -s 257 -n 8 -e '8/1 "%_p"' "${mountname}${file}${loader}");
3003
3004 if [ "${sig}" = 'BootPart' ] ; then
3005 offset=$(hexdump -v -s 241 -n 4 -e '"%d"' "${mountname}${file}${loader}");
3006 dr=$(hexdump -v -s 111 -n 1 -e '"%d"' "${mountname}${file}${loader}");
3007 dr=$((dr - 127));
3008 BFI="${BFI} BootPart in the file ${file}${loader} is trying to chainload sector #${offset} on boot drive #${dr}";
3009 fi
3010
3011 # Grub Legacy, Grub2 (v1.96) and Grub2 (v1.99) have "GRUB" written at 0x17f.
3012 sig=$(hexdump -v -s 383 -n 4 -e '4/1 "%_p"' "${mountname}${file}${loader}");
3013
3014 if [ "${sig}" = 'GRUB' ] ; then
3015 sig2=$(hexdump -v -n 2 -e '/1 "%02x"' "${mountname}${file}${loader}");
3016
3017 # Distinguish Grub Legacy and Grub2 (v1.96) by the first two bytes.
3018 case "${sig2}" in
3019 eb48) stage2_loc "${mountname}${file}${loader}";
3020 BFI="${BFI} Grub Legacy (v${Grub_Version}) in the file ${file}${loader} ${Stage2_Msg}";;
3021 eb4c) grub2_info "${mountname}${file}${loader}" ${drive} 1.96 'file';
3022 BFI="${BFI} Grub2 (v1.96) in the file ${file}${loader} ${Grub2_Msg}.";;
3023 eb63) grub2_info "${mountname}${file}${loader}" ${drive} 1.99 'file';
3024 BFI="${BFI} Grub2 (v1.99) in the file ${file}${loader} ${Grub2_Msg}.";;
3025 esac
3026 fi
3027
3028 # Grub2 (v1.97-1.98) has "GRUB" written at 0x188.
3029 sig=$(hexdump -v -s 392 -n 4 -e '4/1 "%_p"' "${mountname}${file}${loader}");
3030
3031 if [ "${sig}" = 'GRUB' ]; then
3032 grub2_info "${mountname}${file}${loader}" ${drive} 1.97-1.98 'file';
3033 BFI="${BFI} Grub2 (v1.97-1.98) in the file ${file}${loader} ${Grub2_Msg}.";
3034 fi
3035
3036 # Grub2 (v2.00) has "GRUB" written at 0x180.
3037 sig=$(hexdump -v -s 384 -n 4 -e '4/1 "%_p"' "${mountname}${file}${loader}");
3038
3039 if [ "${sig}" = 'GRUB' ]; then
3040 grub2_info "${mountname}${file}${loader}" ${drive} 2.00 'file';
3041 BFI="${BFI} Grub2 (v2.00) in the file ${file}${loader} ${Grub2_Msg}.";
3042 fi
3043 fi
3044 done # End of loop through the files in a particular Boot_Code_Directory.
3045 fi
3046 done # End of the loop through the Boot_Code_Directories.
3047
3048
3049
3050 ## Show the location (offset on disk) of all files in: ##
3051 # - the GrubError18_Files list
3052 # - the SyslinuxError_Files list
3053
3054 cd "${mountname}/";
3055
3056 if [ $( last_block_of_file ${GrubError18_Files} ; echo $? ) -ne 0 ] ; then
3057 titlebar_gen "${name}" ': Location of files loaded by Grub';
3058 printf "%11sGiB - GB%13sFile%33sFragment(s)\n\n" ' ' ' ' ' ' >> "${Log1}";
3059 cat ${Tmp_Log} >> "${Log1}";
3060 fi
3061
3062 if [ $( last_block_of_file ${SyslinuxError_Files} ; echo $? ) -ne 0 ] ; then
3063 titlebar_gen "${name}" ': Location of files loaded by Syslinux';
3064 printf "%11sGiB - GB%13sFile%33sFragment(s)\n\n" ' ' ' ' ' ' >> "${Log1}";
3065 cat ${Tmp_Log} >> "${Log1}";
3066 fi
3067
3068
3069
3070 rm -f ${Tmp_Log};
3071
3072 # Display the version of the COM32(R) modules of Syslinux.
3073
3074 for com32 in *.c32 syslinux/*.c32 extlinux/*.c32 boot/syslinux/*.c32 boot/extlinux/*.c32 ; do
3075
3076 if [ -f "${com32}" ] ; then
3077 # First 5 bytes of the COM32(R) module are a magic number (used by Syslinux too).
3078 com32_version=$(hexdump -n 5 -e '/1 "%02x"' "${com32}");
3079
3080 case ${com32_version} in
3081 b8fe4ccd21) printf ' %-35s: COM32R module (v4.xx)\n' "${com32}" >> ${Tmp_Log};;
3082 b8ff4ccd21) printf ' %-35s: COM32R module (v3.xx)\n' "${com32}" >> ${Tmp_Log};;
3083 *) printf ' %-35s: not a COM32/COM32R module\n' "${com32}" >> ${Tmp_Log};;
3084 esac
3085 fi
3086 done
3087
3088 if [ -f ${Tmp_Log} ] ; then
3089 titlebar_gen "${name}" ': Version of COM32(R) files used by Syslinux';
3090 cat ${Tmp_Log} >> "${Log1}";
3091 fi
3092
3093
3094
3095 cd "${Folder}";
3096
3097
3098
3099 echo > ${Tmp_Log};
3100
3101 if [[ x"${BFI}" != x'' ]] ; then
3102 printf " Boot file info: " >> "${Log}";
3103 printf "${BFI}\n" | fold -s -w 55 | sed -e '/^-------------------------$/ d' -e '2~1s/.*/ &/' >> "${Log}";
3104 fi
3105
3106 printf " Operating System: " >> "${Log}";
3107 echo "${OS}" | fold -s -w 55 | sed -e '2~1s/.*/ &/' >> "${Log}";
3108 printf " Boot files: " >> "${Log}";
3109 echo ${BootFiles} | fold -s -w 55 | sed -e '2~1s/.*/ &/' >> "${Log}";
3110
3111
3112
3113 # If partition was mounted by the script.
3114 if [ x"${CheckMount}" = x'' ] ; then
3115 umount "${mountname}" || umount -l "${mountname}";
3116 fi
3117
3118 # If partition failed to mount.
3119 else
3120 printf " Mounting failed: " >> "${Log}";
3121 cat ${Mount_Error} >> "${Log}";
3122 fi # End of Mounting "if then else".
3123 fi # End of Partition Type "if then else".
3124
3125 echo >> "${Log}";
3126
3127 if [[ -e "${Log}"x ]] ; then
3128 cat "${Log}"x >> "${Log}";
3129 rm "${Log}"x;
3130 fi
3131
3132 if [[ -e "${Log1}"x ]] ; then
3133 cat "${Log1}"x >> "${Log1}";
3134 rm "${Log1}"x;
3135 fi
3136} # End Get_Partition_Info function
3137
3138
3139
3140## "titlebar_gen" generates the ${name}${file} title bar to always be 80 characters in length. ##
3141
3142titlebar_gen () {
3143 local name_file name_file_length equal_signs_line_length equal_signs_line;
3144
3145 name_file="${1}${2}:";
3146 name_file_length=${#name_file};
3147
3148 equal_signs_line_length=$(((80-${name_file_length})/2-1));
3149
3150 # Build "===" string.
3151 printf -v equal_signs_line "%${equal_signs_line_length}s";
3152 printf -v equal_signs_line "%s" "${equal_signs_line// /=}";
3153
3154 if [ "$((${name_file_length}%2))" -eq 1 ]; then
3155 # If ${name_file_length} is odd, add an extra "=" at the end.
3156 printf "\n%s %s %s=\n\n" "${equal_signs_line}" "${name_file}" "${equal_signs_line}" >> "${Log1}";
3157 else
3158 printf "\n%s %s %s\n\n" "${equal_signs_line}" "${name_file}" "${equal_signs_line}" >> "${Log1}";
3159 fi
3160}
3161
3162
3163
3164## Start ##
3165
3166
3167
3168# Center title.
3169BIS_title=$(printf 'Boot Info Script %s [%s]' "${VERSION}" "${RELEASE_DATE}");
3170printf -v BIS_title_space "%$(( ( 80 - ${#BIS_title} ) / 2 - 1 ))s";
3171printf "${BIS_title_space}${BIS_title}\n" > "${Log}";
3172
3173if [ ! -z "${LAST_GIT_COMMIT_SHORTLOG}" ] ; then
3174 printf '\nLast git commit: %s\nCommit date: %s\n' \
3175 "${LAST_GIT_COMMIT_SHORTLOG}" "${LAST_GIT_COMMIT_DATE}" >> "${Log}";
3176fi
3177
3178printf '\n\n============================= Boot Info Summary: ===============================\n\n' >> "${Log}";
3179
3180
3181
3182# Search for hard drives which don't exist, have a corrupted partition table
3183# or don't have a parition table (whole drive is a filesystem).
3184# Information on all hard drives which a valid partition table are stored in
3185# the hard drives arrays: HD?????
3186
3187# id for Filesystem Drives.
3188FSD=0;
3189
3190# Clear blkid cache
3191blkid -g;
3192
3193for drive in ${All_Hard_Drives} ; do
3194 size=$(fdisks ${drive});
3195
3196 PrintBlkid ${drive};
3197
3198 if [ 0 -lt ${size} 2>> ${Trash} ] ; then
3199 if [ x"$(blkid ${drive})" = x'' ] || [ x"$(blkid | grep ${drive}:)" = x'' ] ; then
3200 # Drive is not a filesytem.
3201
3202 size=$((2*size));
3203
3204 HDName[${HI}]=${drive};
3205 HDSize[${HI}]=${size};
3206
3207 # Get and set HDHead[${HI}], HDTrack[${HI}] and HDCylinder[${HI}] all at once.
3208 eval $(fdisk -lu ${drive} 2>> ${Trash} | ${AWK} -F ' ' '$2 ~ "head" { print "HDHead['${HI}']=" $1 "; HDTrack['${HI}']=" $3 "; HDCylinder['${HI}']=" $5 }' );
3209
3210 # Look at the first 4 bytes of the second sector to identify the partition table type.
3211 case $(hexdump -v -s 512 -n 4 -e '"%_u"' ${drive}) in
3212 'EMBR') HDPT[${HI}]='BootIt';;
3213 'EFI ') HDPT[${HI}]='EFI';;
3214 *) HDPT[${HI}]='MSDos';;
3215 esac
3216
3217 HI=$((${HI}+1));
3218 else
3219 # Drive is a filesystem.
3220
3221 if [ $( expr match "$(BlkidTag "${drive}" TYPE)" '.*raid') -eq 0 ] || [ x"$(BlkidTag "${drive}" UUID)" != x'' ] ; then
3222 FilesystemDrives[${FSD}]="${drive}";
3223 ((FSD++));
3224 fi
3225 fi
3226 else
3227 printf "$(basename ${drive}) " >> ${FakeHardDrives};
3228 fi
3229done
3230
3231
3232
3233## Identify the MBR of each hard drive. ##
3234echo 'Identifying MBRs...';
3235
3236for HI in ${!HDName[@]} ; do
3237 drive="${HDName[${HI}]}";
3238 Message="is installed in the MBR of ${drive}";
3239
3240 # Read the whole MBR in hexadecimal format.
3241 MBR_512=$(hexdump -v -n 512 -e '/1 "%02x"' ${drive});
3242
3243 ## Look at the first 2,3,4 or 8 bytes of the hard drive to identify the boot code installed in the MBR. ##
3244 #
3245 # If it is not enough, look at more bytes.
3246
3247 MBR_sig2="${MBR_512:0:4}";
3248 MBR_sig3="${MBR_512:0:6}";
3249 MBR_sig4="${MBR_512:0:8}";
3250 MBR_sig8="${MBR_512:0:16}";
3251
3252 ## Bytes 0x80-0x81 of the MBR. ##
3253 #
3254 # Use it to differentiate between different versions of the same bootloader.
3255
3256 MBR_bytes80to81="${MBR_512:256:4}";
3257
3258
3259 BL=;
3260 case ${MBR_sig2} in
3261
3262 eb48) ## Grub Legacy is in the MBR. ##
3263 BL="Grub Legacy";
3264
3265 # 0x44 contains the offset to the next stage.
3266 offset=$(hexdump -v -s 68 -n 4 -e '"%u"' ${drive});
3267
3268 if [ "${offset}" -ne 1 ] ; then
3269 # Grub Legacy is installed without stage1.5 files.
3270 stage2_loc ${drive};
3271 Message="${Message} and ${Stage2_Msg}";
3272 else
3273 # Grub is installed with stage1.5 files.
3274 Grub_String=$(hexdump -v -s 1042 -n 94 -e '"%_u"' ${drive});
3275 Grub_Version="${Grub_String%%nul*}";
3276
3277 BL="Grub Legacy (v${Grub_Version})";
3278
3279 tmp="/${Grub_String#*/}";
3280 tmp="${tmp%%nul*}";
3281
3282 eval $(echo ${tmp} | ${AWK} '{ print "stage=" $1 "; menu=" $2 }');
3283
3284 [[ x"$menu" = x'' ]] || stage="${stage} and ${menu}";
3285
3286 part_info=$((1045 + ${#Grub_Version}));
3287 eval $(hexdump -v -s ${part_info} -n 2 -e '1/1 "pa=%u; " 1/1 "dr=%u"' ${drive});
3288
3289 dr=$(( ${dr} - 127 ));
3290 pa=$(( ${pa} + 1 ));
3291
3292 if [ "${dr}" -eq 128 ] ; then
3293 Message="${Message} and looks on the same drive in partition #${pa} for ${stage}";
3294 else
3295 Message="${Message} and looks on boot drive #${dr} in partition #${pa} for ${stage}";
3296 fi
3297 fi;;
3298
3299 eb4c) ## Grub2 (v1.96) is in the MBR. ##
3300 BL='Grub2 (v1.96)';
3301
3302 grub2_info ${drive} ${drive} '1.96' 'disk';
3303
3304 Message="${Message} and ${Grub2_Msg}";;
3305
3306 eb63) ## Grub2 is in the MBR. ##
3307 case ${MBR_bytes80to81} in
3308 7c3c) grub2_version='1.97-1.98'; BL='Grub2 (v1.97-1.98)';;
3309 0020) grub2_version='1.99-2.00'; BL='Grub2 (v1.99-2.00)';;
3310 esac
3311
3312 grub2_info ${drive} ${drive} ${grub2_version} 'disk';
3313
3314 # Set a more exact version number (1.99 or 2.00), if '1.99-2.00' was
3315 # passed to the grub2_info function.
3316 BL="Grub2 (v${grub2_version})";
3317
3318 Message="${Message} and ${Grub2_Msg}";;
3319
3320 0ebe) BL='ThinkPad';;
3321 31c0) # Look at the first 8 bytes of the hard drive to identify the boot code installed in the MBR.
3322 case ${MBR_sig8} in
3323 31c08ed0bc007c8e) BL='NetBSD/SUSE generic MBR';;
3324 31c08ed0bc007cfb) BL='Acer PQService MBR';;
3325 esac;;
3326 33c0) # Look at the first 3 bytes of the hard drive to identify the boot code installed in the MBR.
3327 case ${MBR_sig3} in
3328 33c08e) BL='Windows';
3329 case ${MBR_sig8} in
3330 33c08ed0bc007cfb) BL='Windows 2000/XP/2003';;
3331 33c08ed0bc007c8e)
3332 # Look at byte 0xF0-F1: different offset for "TCPA" string.
3333 case "${MBR_512:480:4}" in
3334 fb54) BL='Windows Vista';;
3335 4350) BL='Windows 7/8/2012';;
3336 esac;;
3337 esac;;
3338 33c090) BL='DiskCryptor';;
3339 33c0fa) # Look at bytes 0x5B-5D: different offsets for jump target
3340 case ${MBR_512:182:6} in
3341 0fb6c6) BL='Syslinux GPTMBR (5.10 and higher)';;
3342 bb007c) BL='Syslinux GPTMBR (4.04-5.01)';;
3343 e82101) BL='Syslinux MBR (4.04-4.07)';;
3344 e83501) BL='Syslinux MBR (5.00 and higher)';;
3345 e81001) # Syslinux ALTMBR; look at byte 0xd9 for different version and
3346 # byte 0x1b7 (439) for boot partition
3347 case ${MBR_512:434:2} in
3348 c3) BL='Syslinux ALTMBR (4.04-4.05)';;
3349 c6) BL='Syslinux ALTMBR (4.06 and higher)';;
3350 esac;
3351 BL="${BL} with boot partition 0x${MBR_512:878:2}";;
3352 esac;;
3353 esac;;
3354 33ed) # Look at bytes 0x80-0x81 to be more specific about the Syslinux variant/version.
3355 case ${MBR_bytes80to81} in
3356 407c) BL='ISOhybrid (Syslinux 4.04)';;
3357 83e1) BL='ISOhybrid with partition support (Syslinux 4.04)';;
3358 cd13) BL='ISOhybrid with partition support (Syslinux 4.05 and higher)';;
3359 f7e1) BL='ISOhybrid (Syslinux 4.05 and higher)';;
3360 esac;;
3361 33ff) BL='HP/Gateway';;
3362 b800) BL='Plop';;
3363 ea05)
3364 case ${MBR_sig3} in
3365 ea0500) BL='OpenBSD generic MBR';;
3366 ea0501) BL='XOSL';;
3367 esac;;
3368 ea1e) BL='Truecrypt Boot Loader';;
3369 eb04) BL='Solaris';;
3370 eb31) BL='Paragon';;
3371 eb5e) # Look at the first 3 bytes of the hard drive to identify the boot code installed in the MBR.
3372 case ${MBR_sig3} in
3373 eb5e00) BL='fbinst';;
3374 eb5e80) BL='Grub4Dos';;
3375 eb5e90) BL='WEE';
3376 # Get the embedded menu of WEE.
3377 get_embedded_menu "${drive}" "WEE's (${drive})";;
3378 esac;;
3379 fa31) # Look at the first 3 bytes of the hard drive to identify the boot code installed in the MBR.
3380 case ${MBR_sig3} in
3381 fa31c0) # Look at bytes 0x80-0x81 to be more specific about the Syslinux variant/version.
3382 case ${MBR_bytes80to81} in
3383 0069) BL='ISOhybrid (Syslinux 3.72-3.73)';;
3384 7c66) BL='Syslinux MBR (3.61-4.03)';;
3385 7cb8) BL='Syslinux MBR (3.36-3.51)';;
3386 b442) BL='Syslinux MBR (3.00-3.35)';;
3387 bb00) BL='Syslinux MBR (3.52-3.60)';;
3388 e2f8) # Syslinux pre-4.04; look at bytes 0x82-0x84
3389 case "${MBR_512:260:6}" in
3390 31f65f) BL='Syslinux GPTMBR (4.00-4.03)';;
3391 5e5974) BL='Syslinux GPTMBR (3.72-3.73)';;
3392 5e5958) # look at bytes 0xe-0xf
3393 case "${MBR_512:28:4}" in
3394 528e) BL='Syslinux GPTMBR (3.70-3.71)';;
3395 8ec0) BL='Syslinux GPTMBR (3.74-4.03)';;
3396 esac;;
3397 esac;;
3398 e879) BL='ISOhybrid (Syslinux 3.74-3.80)';;
3399 esac;;
3400 fa31c9) BL='Master Boot LoaDeR';;
3401 fa31ed) # Look at bytes 0x80-0x81 to be more specific about the Syslinux variant/version.
3402 case ${MBR_bytes80to81} in
3403 0069) BL='ISOhybrid (Syslinux 3.72-3.73)';;
3404 0fb6) BL='ISOhybrid with partition support (Syslinux 3.82-3.86)';;
3405 407c) BL='ISOhybrid (Syslinux 3.82-4.03)';;
3406 83e1) BL='ISOhybrid with partition support (Syslinux 4.00-4.03)';;
3407 b6c6) BL='ISOhybrid with partition support (Syslinux 3.81)';;
3408 fbc0) BL='ISOhybrid (Syslinux 3.81)';;
3409 esac;;
3410 esac;;
3411 fa33) BL='MS-DOS 3.30 through Windows 95 (A)';;
3412 fab8) # Look at the first 4 bytes of the hard drive to identify the boot code installed in the MBR.
3413 case ${MBR_sig4} in
3414 fab80000) BL='FreeDOS (eXtended FDisk)';;
3415 fab80010) BL="libparted MBR boot code";;
3416 esac;;
3417 faeb) BL='Lilo';;
3418 fafc) BL='ReactOS';;
3419 fc31) # Look at the first 8 bytes of the hard drive to identify the boot code installed in the MBR.
3420 case ${MBR_sig8} in
3421 fc31c08ed031e48e) BL='install-mbr/Testdisk';;
3422 fc31c08ec08ed88e) BL='boot0 (FreeBSD)';;
3423 esac;;
3424 fc33) BL='GAG';;
3425 fceb) BL='BootIt NG';;
3426 0000) BL='No boot loader';;
3427 esac
3428
3429 if [ x"${BL}" = 'x' ] ; then
3430 BL='No known boot loader';
3431 printf "Unknown MBR on ${drive}\n\n" >> ${Unknown_MBR};
3432 hexdump -v -n 512 -C ${drive} >> ${Unknown_MBR};
3433 echo >> ${Unknown_MBR};
3434 fi
3435
3436
3437 ## Output message at beginning of summary that gives MBR info for each drive: ##
3438
3439 printf ' => ' >> "${Log}";
3440 printf "${BL} ${Message}.\n" | fold -s -w 75 | sed -e '/^-----\.\?$/ d' -e '2~1s/.*/ &/' >> "${Log}";
3441
3442 HDMBR[${HI}]=${BL};
3443done
3444
3445echo >> "${Log}";
3446
3447
3448
3449## Store and Display all the partitions tables. ##
3450
3451for HI in ${!HDName[@]} ; do
3452 drive=${HDName[${HI}]};
3453
3454 echo "Computing Partition Table of ${drive}...";
3455
3456 FP=$((PI+1)); # used if non-MS_DOS partition table is not in use.
3457 FirstPartition[${HI}]=${FP};
3458 PTType=${HDPT[${HI}]};
3459 HDPT[${HI}]='MSDos';
3460
3461 echo "Drive: $(basename ${drive} ) _____________________________________________________________________" >> ${PartitionTable};
3462 fdisk -lu ${drive} 2>> ${Trash} | sed '/omitting/ d' | sed '6,$ d' >> ${PartitionTable};
3463
3464 printf "\n${PTFormat}\n" 'Partition' 'Boot' 'Start Sector' 'End Sector' '# of Sectors' 'Id' 'System' >> ${PartitionTable};
3465
3466 ReadPT ${HI} 0 4 ${PartitionTable} "${PTFormat}" '' 0;
3467
3468 echo >> ${PartitionTable};
3469 LastPartition[${HI}]=${PI};
3470 LP=${PI};
3471
3472 CheckPT ${FirstPartition[${HI}]} ${LastPartition[${HI}]} ${PartitionTable} ${HI};
3473
3474 echo >> ${PartitionTable};
3475 HDPT[${HI}]=${PTType};
3476
3477 case ${PTType} in
3478 BootIt) printf 'BootIt NG Partition Table detected' >> ${PartitionTable};
3479 [[ "${HDMBR[${HI}]}" = 'BootIt NG' ]] || printf ', but does not seem to be used' >> ${PartitionTable};
3480 printf '.\n\n' >> ${PartitionTable};
3481
3482 ReadEMBR ${HI} ${PartitionTable};
3483 echo >> ${PartitionTable};
3484
3485 if [ "${HDMBR[${HI}]}" = 'BootIt NG' ] ; then
3486 LastPartition[${HI}]=${PI};
3487 CheckPT ${FirstPartition[${HI}]} ${LastPartition[${HI}]} ${PartitionTable} ${HI};
3488 else
3489 FirstPartition[${HI}]=${FP};
3490 fi;;
3491 EFI) FirstPartition[${HI}]=$((PI+1));
3492 EFIee=$(hexdump -v -s 450 -n 1 -e '"%x"' ${drive});
3493 printf 'GUID Partition Table detected' >> ${PartitionTable};
3494 [[ "${EFIee}" = 'ee' ]] || printf ', but does not seem to be used' >> ${PartitionTable};
3495 printf '.\n\n' >> ${PartitionTable};
3496
3497 ReadEFI ${HI} ${PartitionTable};
3498 echo >> ${PartitionTable};
3499
3500 if [ "${EFIee}" = 'ee' ] ; then
3501 LastPartition[${HI}]=${PI};
3502 CheckPT ${FirstPartition[${HI}]} ${LastPartition[${HI}]} ${PartitionTable} ${HI};
3503 else
3504 FirstPartition[${HI}]=${FP};
3505 fi;;
3506 esac
3507done
3508
3509
3510
3511## Loop through all Hard Drives. ##
3512
3513for HI in ${!HDName[@]} ; do
3514 drive=${HDName[${HI}]};
3515
3516 ## And then loop through the partitions on that drive. ##
3517 for (( PI = FirstPartition[${HI}]; PI <= LastPartition[${HI}]; PI++ )); do
3518 part_type=${TypeArray[${PI}]}; # Type of the partition according to fdisk
3519 start=${StartArray[${PI}]};
3520 size=${SizeArray[${PI}]};
3521 end=${EndArray[${PI}]};
3522 kind=${KindArray[${PI}]};
3523 system=${SystemArray[${PI}]};
3524
3525 if [[ x"${DeviceArray[${PI}]}" = x'' ]] ; then
3526 name="${NamesArray[${PI}]}";
3527 mountname=$(basename ${drive})"_"${PI};
3528 part=$(losetup -f --show -o $((start*512)) ${drive});
3529 # --sizelimit $((size*512)) --sizelimit seems to be a recently added option for losetup. Failed on Hardy.
3530 else
3531 part="${DeviceArray[${PI}]}";
3532 name=$(basename ${part}); # Name of the partition (/dev/sda8 -> sda8).
3533 mountname=${name};
3534 fi
3535
3536 Get_Partition_Info "${Log}" "${Log1}" "${part}" "${name}" "${mountname}" "${kind}" "${start}" "${end}" "${system}" "${PI}";
3537
3538 [[ "${DeviceArray[${PI}]}" = '' ]] && losetup -d ${part};
3539
3540 done
3541done
3542
3543
3544
3545## Deactivate dmraid's activated by the script. ##
3546
3547if [ x"$InActiveDMRaid" != x'' ] ; then
3548 dmraid -an ${InActiveDMRaid};
3549fi
3550
3551
3552
3553## Search LVM partitions for information. ##
3554#
3555# Only works if the "LVM2"-package is installed.
3556
3557if [ $(type lvs >> ${Trash} 2>> ${Trash} ; echo $?) -eq 0 ] ; then
3558
3559 lvs --nameprefixes --noheadings --options lv_name,vg_name,lv_size,lv_attr --units s | \
3560 while read line ; do
3561 LVM2_VG_NAME= LVM2_LV_NAME= LVM2_LV_SIZE= LVM2_LV_ATTR=
3562 eval "${line}";
3563 if [ -z "${LVM2_VG_NAME}" ] || [ -z "${LVM2_LV_NAME}" ] || [ -z "${LVM2_LV_SIZE}" ] || [ -z "${LVM2_LV_ATTR}" ] ; then
3564 continue
3565 fi
3566 name="${LVM2_VG_NAME}-${LVM2_LV_NAME}";
3567 LVM="/dev/mapper/${LVM2_VG_NAME//-/--}-${LVM2_LV_NAME//-/--}";
3568 LVM_Size=${LVM2_LV_SIZE%s};
3569 LVM_Status=${LVM2_LV_ATTR:4:1};
3570 lvchange -ay ${LVM};
3571 mountname="LVM/${name}";
3572 kind='LVM';
3573 start=0;
3574 end=${LVM_Size};
3575 system='';
3576 PI='';
3577
3578 Get_Partition_Info "${Log}" "${Log1}" "$LVM" "${name}" "${mountname}" "${kind}" "${start}" "${end}" "${system}" "${PI}";
3579
3580 # deactivate all LVM's, which were not active.
3581 [[ "${LVM_Status}" != 'a' ]] && lvchange -an "${LVM}";
3582
3583 done
3584fi
3585
3586
3587
3588## Search MDRaid Partitons for Information ##
3589#
3590# Only works if "mdadm" is installed.
3591
3592if [ $(type mdadm >> ${Trash} 2>> ${Trash} ; echo $?) -eq 0 ] ; then
3593
3594 # All arrays which are already assembled.
3595 MD_Active_Array=$(mdadm --detail --scan | ${AWK} '{ print $2 }');
3596
3597 # Assemble all arrays.
3598 mdadm --assemble --scan;
3599
3600 # All arrays.
3601 MD_Array=$(mdadm --detail --scan | ${AWK} '{ print $2 }');
3602
3603 for MD in ${MD_Array}; do
3604 MD_Size=$(fdisks ${MD}); # size in blocks
3605 MD_Size=$((2*${MD_Size})); # size in sectors
3606 MD_Active=0;
3607
3608 # Check whether MD is active.
3609 for MDA in ${MD_Active_Array}; do
3610 if [[ "${MDA}" = "${MD}" ]] ; then
3611 MD_Active=1;
3612 break;
3613 fi
3614 done
3615
3616 name=${MD:5};
3617 mountname="MDRaid/${name}";
3618 kind="MDRaid";
3619 start=0;
3620 end=${MD_Size};
3621 system='';
3622 PI='';
3623
3624 Get_Partition_Info "${Log}" "${Log1}" "${MD}" "${name}" "${mountname}" "${kind}" "${start}" "${end}" "${system}" "${PI}";
3625
3626 # deactivate all MD_Raid's, which were not active.
3627 [[ "${MD_Active}" -eq 0 ]] && mdadm --stop "${MD}";
3628
3629 done
3630fi
3631
3632
3633
3634## Search filesystem hard drives for information. ##
3635
3636for FD in ${FilesystemDrives[@]} ; do
3637 FD_Size=$(fdisks ${FD}); # size in blocks
3638 FD_Size=$((2*${FD_Size})); # size in sectors
3639 name=${FD:5};
3640 mountname="FD/${name}";
3641 kind="FD";
3642 start=0;
3643 end=${FD_Size};
3644 system='';
3645 PI='';
3646
3647 Get_Partition_Info "${Log}" "${Log1}" "${FD}" "${name}" "${mountname}" "${kind}" "${start}" "${end}" "${system}" "${PI}";
3648
3649done
3650
3651
3652
3653## Drive/partition info. ##
3654
3655printf '============================ Drive/Partition Info: =============================\n\n' >> "${Log}";
3656
3657[ -e ${PartitionTable} ] && cat ${PartitionTable} >> "${Log}" || echo 'no valid partition table found' >> "${Log}";
3658
3659
3660printf '"blkid" output: ________________________________________________________________\n\n' >> "${Log}";
3661
3662printf "${BlkidFormat}" Device UUID TYPE LABEL >> "${Log}";
3663
3664echo >> "${Log}";
3665
3666for dev in $(blkid -o device | sort); do
3667 PrintBlkid ${dev} '_summary';
3668done
3669
3670cat "${BLKID}_summary" >> "${Log}";
3671echo >> "${Log}";
3672
3673
3674
3675if [ $(ls -l /dev/disk/by-id 2>> ${Trash} | wc -l) -gt 1 ] ; then
3676 printf '========================= "ls -l /dev/disk/by-id" output: ======================\n\n' >> "${Log}";
3677 ls -l /dev/disk/by-id >> "${Log}";
3678 echo >> "${Log}";
3679fi
3680
3681
3682
3683if [ $(ls -R /dev/mapper 2>> ${Trash} | wc -l) -gt 2 ] ; then
3684 printf '========================= "ls -R /dev/mapper/" output: =========================\n\n' >> "${Log}";
3685 ls -R /dev/mapper >> "${Log}";
3686 echo >> "${Log}";
3687fi
3688
3689
3690
3691## Mount points. ##
3692
3693printf '================================ Mount points: =================================\n\n' >> "${Log}";
3694
3695MountFormat='%-16s %-24s %-10s %s\n';
3696
3697printf "${MountFormat}\n" 'Device' 'Mount_Point' 'Type' 'Options' >> "${Log}";
3698
3699# No idea for which mount version this is even needed.
3700# original:
3701# mount | grep ' / '| grep -v '^/'| sed 's/ on /'$Fis'/' |sed 's/ type /'$Fis'/'|sed 's/ (/'$Fis'(/'| gawk -F $Fis '{printf "'"$MountFormat"'", $1, $2, $3, $4 }'>>"$Log";
3702# new:
3703# mount | sort | gawk -F "\t" '$0 ~ " / " { if ($1 !~ "^/") { sub(" on ", "\t", $0); sub(" type ", "\t", $0); optionsstart=index($3, " ("); printf "'"${MountFormat}"'", $1, $2, substr($3, 1, optionsstart - 1), substr($3, optionsstart + 1) } } END { printf "\n" }' >> "${Log}";
3704
3705mount | sort | ${AWK} -F "\t" '$0 ~ "^/dev" \
3706 { sub(" on ", "\t", $0); sub(" type ", "\t", $0); optionsstart=index($3, " ("); \
3707 printf "'"${MountFormat}"'", $1, $2, substr($3, 1, optionsstart - 1), substr($3, optionsstart + 1) } END { printf "\n" }' >> "${Log}";
3708
3709
3710
3711## Write the content of Log1 to the log file. ##
3712
3713[ -e "${Log1}" ] && cat "${Log1}" >> "${Log}";
3714echo >> "${Log}";
3715
3716
3717
3718## Add unknown MBRs/Boot Sectors to the log file, if any. ##
3719
3720if [ -e ${Unknown_MBR} ] ; then
3721 printf '======================== Unknown MBRs/Boot Sectors/etc: ========================\n\n' >> "${Log}";
3722 cat ${Unknown_MBR} >> "${Log}";
3723 echo >> "${Log}";
3724fi
3725
3726
3727
3728## Add fake hard drives to the log file, if any. ##
3729
3730if [ -e ${FakeHardDrives} ] ; then
3731 printf "========= Devices which don't seem to have a corresponding hard drive: =========\n\n" >> "${Log}";
3732 cat ${FakeHardDrives} >> "${Log}";
3733 printf "\n\n" >> "${Log}";
3734fi
3735
3736
3737
3738## Write the Error Log to the log file. ##
3739
3740if [ -s ${Error_Log} ] ; then
3741 printf '=============================== StdErr Messages: ===============================\n\n' >> "${Log}";
3742 cat ${Error_Log} >> "${Log}";
3743fi
3744
3745
3746
3747## Write a final newline. ##
3748
3749echo >> "${Log}";
3750
3751
3752
3753if [ ${stdout_output} -eq 1 ] ; then
3754 ## If --stdout is specified, show the output.
3755 cat "${Log}";
3756else
3757 ## Copy the log file to RESULTS file and make the user the owner of RESULTS file. ##
3758
3759 cp "${Log}" "${LogFile}";
3760
3761 if [ "${SUDO_UID}:${SUDO_GID}" != ':' ] ; then
3762 chown "${SUDO_UID}:${SUDO_GID}" "${LogFile}";
3763 fi
3764
3765
3766
3767 ## gzip the RESULTS file, for easy uploading. ##
3768 #
3769 # gzip a copy of the RESULTS file only when -g or --gzip is passed on the command line.
3770 #
3771 # ./bootinfoscript -g <outputfile>
3772 # ./bootinfoscript --gzip <outputfile>
3773
3774 if [ ${gzip_output} -eq 1 ] ; then
3775 cat "${LogFile}" | gzip -9 > "${LogFile}.gz";
3776
3777 if [ "${SUDO_UID}:${SUDO_GID}" != ':' ] ; then
3778 chown "${SUDO_UID}:${SUDO_GID}" "${LogFile}.gz";
3779 fi
3780 fi
3781
3782
3783
3784 ## Reset the Standard Output to the Terminal. ##
3785 #
3786 # exec 1>&-;
3787 # exec 1>&6;
3788 # exec 6>&-;
3789
3790
3791
3792 printf '\nFinished. The results are in the file "%s"\nlocated in "%s".\n\n' "$(basename "${LogFile}")" "${Dir}/";
3793fi
3794
3795exit 0;