]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libdisk/rules.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libdisk / rules.c
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$");
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 }