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