1 /*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 */
9
10 #include <sys/cdefs.h>
11 __FBSDID("$FreeBSD: stable/9/lib/libdisk/rules.c 127595 2004-03-30 01:39:00Z kuriyama $");
12
13 #include <sys/types.h>
14 #include <sys/stdint.h>
15 #include <sys/disklabel.h>
16 #ifdef PC98
17 #include <sys/diskpc98.h>
18 #else
19 #include <sys/diskmbr.h>
20 #endif
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include "libdisk.h"
26
27 int
Track_Aligned(const struct disk * d,daddr_t offset)28 Track_Aligned(const struct disk *d, daddr_t offset)
29 {
30 #ifndef __ia64__
31 if (!d->bios_sect)
32 return 1;
33 if (offset % d->bios_sect)
34 return 0;
35 #endif /* __ia64__ */
36 return 1;
37 }
38
39 daddr_t
Prev_Track_Aligned(const struct disk * d,daddr_t offset)40 Prev_Track_Aligned(const struct disk *d, daddr_t offset)
41 {
42 #ifndef __ia64__
43 if (!d->bios_sect)
44 return offset;
45 return (offset / d->bios_sect) * d->bios_sect;
46 #else
47 return 1;
48 #endif
49 }
50
51 daddr_t
Next_Track_Aligned(const struct disk * d,daddr_t offset)52 Next_Track_Aligned(const struct disk *d, daddr_t offset)
53 {
54 #ifndef __ia64__
55 if (!d->bios_sect)
56 return offset;
57 return Prev_Track_Aligned(d, offset + d->bios_sect-1);
58 #else
59 return 1;
60 #endif
61 }
62
63 static int
Cyl_Aligned(const struct disk * d,daddr_t offset)64 Cyl_Aligned(const struct disk *d, daddr_t offset)
65 {
66 #ifndef __ia64__
67 if (!d->bios_sect || !d->bios_hd)
68 return 1;
69 if (offset % (d->bios_sect * d->bios_hd))
70 return 0;
71 #endif
72 return 1;
73 }
74
75 daddr_t
Prev_Cyl_Aligned(const struct disk * d,daddr_t offset)76 Prev_Cyl_Aligned(const struct disk *d, daddr_t offset)
77 {
78 #ifndef __ia64__
79 if (!d->bios_sect || !d->bios_hd)
80 return offset;
81 return (offset / (d->bios_sect * d->bios_hd)) * d->bios_sect *
82 d->bios_hd;
83 #else
84 return 1;
85 #endif
86 }
87
88 daddr_t
Next_Cyl_Aligned(const struct disk * d,daddr_t offset)89 Next_Cyl_Aligned(const struct disk *d, daddr_t offset)
90 {
91 #ifndef __ia64__
92 if (!d->bios_sect || !d->bios_hd)
93 return offset;
94 return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd) - 1);
95 #else
96 return 1;
97 #endif
98 }
99
100 /*
101 * Rule#0:
102 * Chunks of type 'whole' can have max NDOSPART children.
103 * Only one of them can have the "active" flag
104 */
105 static void
Rule_000(__unused const struct disk * d,const struct chunk * c,char * msg)106 Rule_000(__unused const struct disk *d, const struct chunk *c, char *msg)
107 {
108 #ifdef PC98
109 int i = 0;
110 #else
111 int i = 0, j = 0;
112 #endif
113 struct chunk *c1;
114
115 if (c->type != whole)
116 return;
117 for (c1 = c->part; c1; c1 = c1->next) {
118 if (c1->type != unused)
119 continue;
120 #ifndef PC98
121 if (c1->flags & CHUNK_ACTIVE)
122 j++;
123 #endif
124 i++;
125 }
126 if (i > NDOSPART)
127 sprintf(msg + strlen(msg),
128 "%d is too many children of the 'whole' chunk."
129 " Max is %d\n", i, NDOSPART);
130 #ifndef PC98
131 if (j > 1)
132 sprintf(msg + strlen(msg),
133 "Too many active children of 'whole'");
134 #endif
135 }
136
137 /*
138 * Rule#1:
139 * All children of 'whole' and 'extended' must be track-aligned.
140 * Exception: the end can be unaligned if it matches the end of 'whole'
141 */
142 static void
Rule_001(const struct disk * d,const struct chunk * c,char * msg)143 Rule_001(const struct disk *d, const struct chunk *c, char *msg)
144 {
145 struct chunk *c1;
146
147 if (c->type != whole && c->type != extended)
148 return;
149 for (c1 = c->part; c1; c1 = c1->next) {
150 if (c1->type == unused)
151 continue;
152 c1->flags |= CHUNK_ALIGN;
153 #ifdef PC98
154 if (!Cyl_Aligned(d, c1->offset))
155 #else
156 if (!Track_Aligned(d, c1->offset))
157 #endif
158 sprintf(msg + strlen(msg),
159 #ifdef PC98
160 "chunk '%s' [%jd..%jd] does not start"
161 " on a cylinder boundary\n",
162 #else
163 "chunk '%s' [%jd..%jd] does not start"
164 " on a track boundary\n",
165 #endif
166 c1->name, (intmax_t)c1->offset, (intmax_t)c1->end);
167 if ((c->type == whole || c->end == c1->end)
168 || Cyl_Aligned(d, c1->end + 1))
169 ;
170 else
171 sprintf(msg + strlen(msg),
172 "chunk '%s' [%jd..%jd] does not end"
173 " on a cylinder boundary\n",
174 c1->name, (intmax_t)c1->offset, (intmax_t)c1->end);
175 }
176 }
177
178 /*
179 * Rule#2:
180 * Max one 'fat' as child of 'whole'
181 */
182 static void
Rule_002(__unused const struct disk * d,const struct chunk * c,char * msg)183 Rule_002(__unused const struct disk *d, const struct chunk *c, char *msg)
184 {
185 int i;
186 struct chunk *c1;
187
188 if (c->type != whole)
189 return;
190 for (i = 0, c1 = c->part; c1; c1 = c1->next) {
191 if (c1->type != fat)
192 continue;
193 i++;
194 }
195 if (i > 1) {
196 sprintf(msg + strlen(msg),
197 "Max one 'fat' allowed as child of 'whole'\n");
198 }
199 }
200
201 /*
202 * Rule#3:
203 * Max one extended as child of 'whole'
204 */
205 static void
Rule_003(__unused const struct disk * d,const struct chunk * c,char * msg)206 Rule_003(__unused const struct disk *d, const struct chunk *c, char *msg)
207 {
208 int i;
209 struct chunk *c1;
210
211 if (c->type != whole)
212 return;
213 for (i = 0, c1 = c->part; c1; c1 = c1->next) {
214 if (c1->type != extended)
215 continue;
216 i++;
217 }
218 if (i > 1) {
219 sprintf(msg + strlen(msg),
220 "Max one 'extended' allowed as child of 'whole'\n");
221 }
222 }
223
224 /*
225 * Rule#4:
226 * Max seven 'part' as children of 'freebsd'
227 * Max one CHUNK_IS_ROOT child per 'freebsd'
228 */
229 static void
Rule_004(__unused const struct disk * d,const struct chunk * c,char * msg)230 Rule_004(__unused const struct disk *d, const struct chunk *c, char *msg)
231 {
232 int i = 0, k = 0;
233 struct chunk *c1;
234
235 if (c->type != freebsd)
236 return;
237
238 for (c1 = c->part; c1; c1 = c1->next) {
239 if (c1->type != part)
240 continue;
241 if (c1->flags & CHUNK_IS_ROOT)
242 k++;
243 i++;
244 }
245 if (i > 7) {
246 sprintf(msg + strlen(msg),
247 "Max seven partitions per freebsd slice\n");
248 }
249 if (k > 1) {
250 sprintf(msg + strlen(msg),
251 "Max one root partition child per freebsd slice\n");
252 }
253 }
254
255 static void
Check_Chunk(const struct disk * d,const struct chunk * c,char * msg)256 Check_Chunk(const struct disk *d, const struct chunk *c, char *msg)
257 {
258
259 switch (platform) {
260 case p_i386:
261 case p_amd64:
262 Rule_000(d, c, msg);
263 Rule_001(d, c, msg);
264 Rule_002(d, c, msg);
265 Rule_003(d, c, msg);
266 Rule_004(d, c, msg);
267 if (c->part)
268 Check_Chunk(d, c->part, msg);
269 if (c->next)
270 Check_Chunk(d, c->next, msg);
271 break;
272 case p_pc98:
273 Rule_000(d, c, msg);
274 Rule_001(d, c, msg);
275 Rule_004(d, c, msg);
276 if (c->part)
277 Check_Chunk(d, c->part, msg);
278 if (c->next)
279 Check_Chunk(d, c->next, msg);
280 break;
281 default:
282 break;
283 }
284 }
285
286 char *
CheckRules(const struct disk * d)287 CheckRules(const struct disk *d)
288 {
289 char msg[BUFSIZ];
290
291 *msg = '\0';
292 Check_Chunk(d, d->chunks, msg);
293 if (*msg)
294 return strdup(msg);
295 return 0;
296 }
297