]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libdisk/rules.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / lib / libdisk / rules.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@login.dknet.dk> 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  * $FreeBSD$
10  *
11  */
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 #include <err.h>
21 #include "libdisk.h"
22
23 int
24 Track_Aligned(struct disk *d, u_long offset)
25 {
26         if (!d->bios_sect)
27                 return 1;
28         if (offset % d->bios_sect)
29                 return 0;
30         return 1;
31 }
32
33 u_long
34 Prev_Track_Aligned(struct disk *d, u_long offset)
35 {
36         if (!d->bios_sect)
37                 return offset;
38         return (offset / d->bios_sect) * d->bios_sect;
39 }
40
41 u_long
42 Next_Track_Aligned(struct disk *d, u_long offset)
43 {
44         if (!d->bios_sect)
45                 return offset;
46         return Prev_Track_Aligned(d,offset + d->bios_sect-1);
47 }
48
49 int
50 Cyl_Aligned(struct disk *d, u_long offset)
51 {
52         if (!d->bios_sect || !d->bios_hd)
53                 return 1;
54         if (offset % (d->bios_sect * d->bios_hd))
55                 return 0;
56         return 1;
57 }
58
59 u_long
60 Prev_Cyl_Aligned(struct disk *d, u_long offset)
61 {
62         if (!d->bios_sect || !d->bios_hd)
63                 return offset;
64         return (offset / (d->bios_sect*d->bios_hd)) * d->bios_sect * d->bios_hd;
65 }
66
67 u_long
68 Next_Cyl_Aligned(struct disk *d, u_long offset)
69 {
70         if (!d->bios_sect || !d->bios_hd)
71                 return offset;
72         return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd)-1);
73 }
74
75 /*
76  *  Rule#0:
77  *      Chunks of type 'whole' can have max NDOSPART children.
78  *      Only one of them can have the "active" flag
79  */
80 void
81 Rule_000(struct disk *d, struct chunk *c, char *msg)
82 {
83 #ifdef PC98
84         int i=0;
85 #else
86         int i=0,j=0;
87 #endif
88         struct chunk *c1;
89
90         if (c->type != whole)
91                 return;
92         for (c1=c->part; c1; c1=c1->next) {
93                 if (c1->type != unused) continue;
94 #ifndef PC98
95                 if (c1->flags & CHUNK_ACTIVE)
96                         j++;
97 #endif
98                 i++;
99         }
100         if (i > NDOSPART)
101                 sprintf(msg+strlen(msg),
102         "%d is too many children of the 'whole' chunk.  Max is %d\n",
103                         i, NDOSPART);
104 #ifndef PC98
105         if (j > 1)
106                 sprintf(msg+strlen(msg),
107         "Too many active children of 'whole'");
108 #endif
109 }
110
111 /*
112  * Rule#1:
113  *      All children of 'whole' and 'extended'  must be track-aligned.
114  *      Exception: the end can be unaligned if it matches the end of 'whole'
115  */
116 void
117 Rule_001(struct disk *d, struct chunk *c, char *msg)
118 {
119         int i;
120         struct chunk *c1;
121
122         if (c->type != whole && c->type != extended)
123                 return;
124         for (i=0, c1=c->part; c1; c1=c1->next) {
125                 if (c1->type == unused) continue;
126                 c1->flags |= CHUNK_ALIGN;
127 #ifdef PC98
128                 if (!Cyl_Aligned(d,c1->offset))
129 #else
130                 if (!Track_Aligned(d,c1->offset))
131 #endif
132                         sprintf(msg+strlen(msg),
133 #ifdef PC98
134                     "chunk '%s' [%ld..%ld] does not start on a cylinder boundary\n",
135 #else
136                     "chunk '%s' [%ld..%ld] does not start on a track boundary\n",
137 #endif
138                                 c1->name,c1->offset,c1->end);
139                 if ((c->type == whole || c->end == c1->end)
140                     || Cyl_Aligned(d,c1->end+1))
141                         ;
142                 else
143                         sprintf(msg+strlen(msg),
144                     "chunk '%s' [%ld..%ld] does not end on a cylinder boundary\n",
145                                 c1->name,c1->offset,c1->end);
146         }
147 }
148
149 /*
150  * Rule#2:
151  *      Max one 'fat' as child of 'whole'
152  */
153 void
154 Rule_002(struct disk *d, struct chunk *c, char *msg)
155 {
156 #ifndef PC98
157         int i;
158         struct chunk *c1;
159
160         if (c->type != whole)
161                 return;
162         for (i=0, c1=c->part; c1; c1=c1->next) {
163                 if (c1->type != fat)
164                         continue;
165                 i++;
166         }
167         if (i > 1) {
168                 sprintf(msg+strlen(msg),
169                     "Max one 'fat' allowed as child of 'whole'\n");
170         }
171 #endif
172 }
173
174 /*
175  * Rule#3:
176  *      Max one extended as child of 'whole'
177  */
178 void
179 Rule_003(struct disk *d, struct chunk *c, char *msg)
180 {
181 #ifndef PC98
182         int i;
183         struct chunk *c1;
184
185         if (c->type != whole)
186                 return;
187         for (i=0, c1=c->part; c1; c1=c1->next) {
188                 if (c1->type != extended)
189                         continue;
190                 i++;
191         }
192         if (i > 1) {
193                 sprintf(msg+strlen(msg),
194                     "Max one 'extended' allowed as child of 'whole'\n");
195         }
196 #endif
197 }
198
199 /*
200  * Rule#4:
201  *      Max seven 'part' as children of 'freebsd'
202  *      Max one CHUNK_IS_ROOT child per 'freebsd'
203  *      If Bad144, space for table must exist.
204  *      If Bad144 & root, bad144 table must be inside 1024
205  */
206 void
207 Rule_004(struct disk *d, struct chunk *c, char *msg)
208 {
209         int i=0,k=0;
210         struct chunk *c1;
211
212         if (c->type != freebsd)
213                 return;
214
215         for (c1=c->part; c1; c1=c1->next) {
216                 if (c1->type != part)
217                         continue;
218                 if (c1->flags & CHUNK_IS_ROOT) {
219                         k++;
220 #ifndef PC98
221                         if (c1->flags & CHUNK_PAST_1024)
222                                 sprintf(msg+strlen(msg),
223             "Root filesystem extends past cylinder 1024, and cannot be booted from\n");
224 #endif
225                 }
226                 i++;
227         }
228         if (i > 7) {
229                 sprintf(msg+strlen(msg),
230                     "Max seven partitions per freebsd slice\n");
231         }
232         if (k > 1) {
233                 sprintf(msg+strlen(msg),
234                     "Max one root partition child per freebsd slice\n");
235         }
236 }
237
238 void
239 Check_Chunk(struct disk *d, struct chunk *c, char *msg)
240 {
241         Rule_000(d,c,msg);
242         Rule_001(d,c,msg);
243         Rule_002(d,c,msg);
244         Rule_003(d,c,msg);
245         Rule_004(d,c,msg);
246         if (c->part)
247                 Check_Chunk(d,c->part,msg);
248         if (c->next)
249                 Check_Chunk(d,c->next,msg);
250
251 #ifndef PC98
252         if (c->end >= 1024*d->bios_hd*d->bios_sect)
253                 c->flags |= CHUNK_PAST_1024;
254         else
255                 c->flags &= ~CHUNK_PAST_1024;
256 #endif
257 }
258
259 char *
260 CheckRules(struct disk *d)
261 {
262         char msg[BUFSIZ];
263
264         *msg = '\0';
265         Check_Chunk(d,d->chunks,msg);
266         if (*msg)
267                 return strdup(msg);
268         return 0;
269 }
270
271 char *
272 ChunkCanBeRoot(struct chunk *c)
273 {
274         struct chunk *c1;
275         struct disk *d = c->disk;
276         char msg[BUFSIZ];
277
278         *msg = '\0';
279 #ifndef PC98
280         if (c->flags & CHUNK_PAST_1024) {
281                 strcat(msg,
282 "The root partition must end before cylinder 1024 seen from\n");
283                 strcat(msg,
284 "the BIOS' point of view, or it cannot be booted from.\n");
285                 return strdup(msg);
286         }
287 #endif
288         for (c1=d->chunks->part;;) {
289                 for (; c1; c1=c1->next)
290                         if (c1->offset <= c->offset && c1->end >= c->end)
291                                 break;
292                 if (!c1) {
293                         strcat(msg,
294 "Internal trouble, cannot find this chunk in the chunk-tree\n");
295                         return strdup(msg);
296                 }
297                 if (c1->type == freebsd)
298                         break;
299                 c1 = c1->part;
300         }
301
302 #ifndef PC98
303         if (c1->type != freebsd) {
304                 strcat(msg,
305 "The root partition must be in a FreeBSD slice, otherwise\n");
306                 strcat(msg,
307 "the kernel cannot be booted from it\n");
308                 return strdup(msg);
309         }
310 #endif
311
312         return NULL;
313 }