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