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