]> code.delx.au - refind/blob - gptsync/showpart.c
More flexible packaging script.
[refind] / gptsync / showpart.c
1 /*
2 * gptsync/showpart.c
3 * Platform-independent code for analyzing hard disk partitioning
4 *
5 * Copyright (c) 2006 Christoph Pfisterer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "gptsync.h"
38
39 //
40 // memory string search
41 //
42
43 static INTN FindMem(VOID *Buffer, UINTN BufferLength, VOID *SearchString, UINTN SearchStringLength)
44 {
45 UINT8 *BufferPtr;
46 UINTN Offset;
47
48 BufferPtr = Buffer;
49 BufferLength -= SearchStringLength;
50 for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) {
51 if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0)
52 return (INTN)Offset;
53 }
54
55 return -1;
56 }
57
58 //
59 // detect boot code
60 //
61
62 static UINTN detect_bootcode(UINT64 partlba, CHARN **bootcodename)
63 {
64 UINTN status;
65 BOOLEAN bootable;
66
67 // read MBR data
68 status = read_sector(partlba, sector);
69 if (status != 0)
70 return status;
71
72 // check bootable signature
73 if (*((UINT16 *)(sector + 510)) == 0xaa55 && sector[0] != 0)
74 bootable = TRUE;
75 else
76 bootable = FALSE;
77 *bootcodename = NULL;
78
79 // detect specific boot codes
80 if (CompareMem(sector + 2, "LILO", 4) == 0 ||
81 CompareMem(sector + 6, "LILO", 4) == 0) {
82 *bootcodename = STR("LILO");
83
84 } else if (CompareMem(sector + 3, "SYSLINUX", 8) == 0) {
85 *bootcodename = STR("SYSLINUX");
86
87 } else if (FindMem(sector, 512, "ISOLINUX", 8) >= 0) {
88 *bootcodename = STR("ISOLINUX");
89
90 } else if (FindMem(sector, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) {
91 *bootcodename = STR("GRUB");
92
93 } else if ((*((UINT32 *)(sector + 502)) == 0 &&
94 *((UINT32 *)(sector + 506)) == 50000 &&
95 *((UINT16 *)(sector + 510)) == 0xaa55) ||
96 FindMem(sector, 512, "Starting the BTX loader", 23) >= 0) {
97 *bootcodename = STR("FreeBSD");
98
99 } else if (FindMem(sector, 512, "!Loading", 8) >= 0 ||
100 FindMem(sector, 512, "/cdboot\0/CDBOOT\0", 16) >= 0) {
101 *bootcodename = STR("OpenBSD");
102
103 } else if (FindMem(sector, 512, "Not a bootxx image", 18) >= 0) {
104 *bootcodename = STR("NetBSD");
105
106 } else if (FindMem(sector, 512, "NTLDR", 5) >= 0) {
107 *bootcodename = STR("Windows NTLDR");
108
109 } else if (FindMem(sector, 512, "BOOTMGR", 7) >= 0) {
110 *bootcodename = STR("Windows BOOTMGR (Vista)");
111
112 } else if (FindMem(sector, 512, "CPUBOOT SYS", 11) >= 0 ||
113 FindMem(sector, 512, "KERNEL SYS", 11) >= 0) {
114 *bootcodename = STR("FreeDOS");
115
116 } else if (FindMem(sector, 512, "OS2LDR", 6) >= 0 ||
117 FindMem(sector, 512, "OS2BOOT", 7) >= 0) {
118 *bootcodename = STR("eComStation");
119
120 } else if (FindMem(sector, 512, "Be Boot Loader", 14) >= 0) {
121 *bootcodename = STR("BeOS");
122
123 } else if (FindMem(sector, 512, "yT Boot Loader", 14) >= 0) {
124 *bootcodename = STR("ZETA");
125
126 } else if (FindMem(sector, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) {
127 *bootcodename = STR("Haiku");
128
129 }
130
131 if (FindMem(sector, 512, "Non-system disk", 15) >= 0) // dummy FAT boot sector
132 *bootcodename = STR("None (Non-system disk message)");
133
134 // TODO: Add a note if a specific code was detected, but the sector is not bootable?
135
136 if (*bootcodename == NULL) {
137 if (bootable)
138 *bootcodename = STR("Unknown, but bootable");
139 else
140 *bootcodename = STR("None");
141 }
142
143 return 0;
144 }
145
146 //
147 // check one partition
148 //
149
150 static UINTN analyze_part(UINT64 partlba)
151 {
152 UINTN status;
153 UINTN i;
154 CHARN *bootcodename;
155 UINTN parttype;
156 CHARN *fsname;
157
158 if (partlba == 0)
159 Print(L"\nMBR contents:\n");
160 else
161 Print(L"\nPartition at LBA %lld:\n", partlba);
162
163 // detect boot code
164 status = detect_bootcode(partlba, &bootcodename);
165 if (status)
166 return status;
167 Print(L" Boot Code: %s\n", bootcodename);
168
169 if (partlba == 0)
170 return 0; // short-circuit MBR analysis
171
172 // detect file system
173 status = detect_mbrtype_fs(partlba, &parttype, &fsname);
174 if (status)
175 return status;
176 Print(L" File System: %s\n", fsname);
177
178 // cross-reference with partition table
179 for (i = 0; i < gpt_part_count; i++) {
180 if (gpt_parts[i].start_lba == partlba) {
181 Print(L" Listed in GPT as partition %d, type %s\n", i+1,
182 gpt_parts[i].gpt_parttype->name);
183 }
184 }
185 for (i = 0; i < mbr_part_count; i++) {
186 if (mbr_parts[i].start_lba == partlba) {
187 Print(L" Listed in MBR as partition %d, type %02x %s%s\n", i+1,
188 mbr_parts[i].mbr_type,
189 mbr_parttype_name(mbr_parts[i].mbr_type),
190 mbr_parts[i].active ? STR(", active") : STR(""));
191 }
192 }
193
194 return 0;
195 }
196
197 //
198 // check all partitions
199 //
200
201 static UINTN analyze_parts(VOID)
202 {
203 UINTN i, k;
204 UINTN status;
205 BOOLEAN is_dupe;
206
207 // check MBR (bootcode only)
208 status = analyze_part(0);
209 if (status)
210 return status;
211
212 // check partitions listed in GPT
213 for (i = 0; i < gpt_part_count; i++) {
214 status = analyze_part(gpt_parts[i].start_lba);
215 if (status)
216 return status;
217 }
218
219 // check partitions listed in MBR, but not in GPT
220 for (i = 0; i < mbr_part_count; i++) {
221 if (mbr_parts[i].start_lba == 1 && mbr_parts[i].mbr_type == 0xee)
222 continue; // skip EFI Protective entry
223
224 is_dupe = FALSE;
225 for (k = 0; k < gpt_part_count; k++)
226 if (gpt_parts[k].start_lba == mbr_parts[i].start_lba)
227 is_dupe = TRUE;
228
229 if (!is_dupe) {
230 status = analyze_part(mbr_parts[i].start_lba);
231 if (status)
232 return status;
233 }
234 }
235
236 return 0;
237 }
238
239 //
240 // display algorithm entry point
241 //
242
243 UINTN showpart(VOID)
244 {
245 UINTN status = 0;
246 UINTN status_gpt, status_mbr;
247
248 // get full information from disk
249 status_gpt = read_gpt();
250 status_mbr = read_mbr();
251 if (status_gpt != 0 || status_mbr != 0)
252 return (status_gpt || status_mbr);
253
254 // analyze all partitions
255 status = analyze_parts();
256 if (status != 0)
257 return status;
258
259 return status;
260 }