rules.c revision 54627
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: head/lib/libdisk/rules.c 54627 1999-12-15 08:33:56Z jkh $
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
23int
24Track_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
33u_long
34Prev_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
41u_long
42Next_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
49int
50Cyl_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
59u_long
60Prev_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
67u_long
68Next_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 */
80void
81Rule_000(struct disk *d, struct chunk *c, char *msg)
82{
83	int i=0,j=0;
84	struct chunk *c1;
85
86	if (c->type != whole)
87		return;
88	for (c1=c->part; c1; c1=c1->next) {
89		if (c1->type != unused) continue;
90		if (c1->flags & CHUNK_ACTIVE)
91			j++;
92		i++;
93	}
94	if (i > NDOSPART)
95		sprintf(msg+strlen(msg),
96	"%d is too many children of the 'whole' chunk.  Max is %d\n",
97			i, NDOSPART);
98	if (j > 1)
99		sprintf(msg+strlen(msg),
100	"Too many active children of 'whole'");
101}
102
103/*
104 * Rule#1:
105 *	All children of 'whole' and 'extended'  must be track-aligned.
106 *	Exception: the end can be unaligned if it matches the end of 'whole'
107 */
108void
109Rule_001(struct disk *d, struct chunk *c, char *msg)
110{
111	int i;
112	struct chunk *c1;
113
114	if (c->type != whole && c->type != extended)
115		return;
116	for (i=0, c1=c->part; c1; c1=c1->next) {
117		if (c1->type == unused) continue;
118		c1->flags |= CHUNK_ALIGN;
119		if (!Track_Aligned(d,c1->offset))
120			sprintf(msg+strlen(msg),
121		    "chunk '%s' [%ld..%ld] does not start on a track boundary\n",
122				c1->name,c1->offset,c1->end);
123		if ((c->type == whole || c->end == c1->end)
124		    || Cyl_Aligned(d,c1->end+1))
125			;
126		else
127			sprintf(msg+strlen(msg),
128		    "chunk '%s' [%ld..%ld] does not end on a cylinder boundary\n",
129				c1->name,c1->offset,c1->end);
130	}
131}
132
133/*
134 * Rule#2:
135 *	Max one 'fat' as child of 'whole'
136 */
137void
138Rule_002(struct disk *d, struct chunk *c, char *msg)
139{
140	int i;
141	struct chunk *c1;
142
143	if (c->type != whole)
144		return;
145	for (i=0, c1=c->part; c1; c1=c1->next) {
146		if (c1->type != fat)
147			continue;
148		i++;
149	}
150	if (i > 1) {
151		sprintf(msg+strlen(msg),
152		    "Max one 'fat' allowed as child of 'whole'\n");
153	}
154}
155
156/*
157 * Rule#3:
158 *	Max one extended as child of 'whole'
159 */
160void
161Rule_003(struct disk *d, struct chunk *c, char *msg)
162{
163	int i;
164	struct chunk *c1;
165
166	if (c->type != whole)
167		return;
168	for (i=0, c1=c->part; c1; c1=c1->next) {
169		if (c1->type != extended)
170			continue;
171		i++;
172	}
173	if (i > 1) {
174		sprintf(msg+strlen(msg),
175		    "Max one 'extended' allowed as child of 'whole'\n");
176	}
177}
178
179/*
180 * Rule#4:
181 *	Max seven 'part' as children of 'freebsd'
182 *	Max one CHUNK_IS_ROOT child per 'freebsd'
183 *	If Bad144, space for table must exist.
184 *	If Bad144 & root, bad144 table must be inside 1024
185 */
186void
187Rule_004(struct disk *d, struct chunk *c, char *msg)
188{
189	int i=0,k=0;
190	struct chunk *c1;
191
192	if (c->type != freebsd)
193		return;
194
195	for (c1=c->part; c1; c1=c1->next) {
196		if (c1->type != part)
197			continue;
198		if (c1->flags & CHUNK_IS_ROOT) {
199			k++;
200			if (c1->flags & CHUNK_PAST_1024)
201				sprintf(msg+strlen(msg),
202	    "Root filesystem extends past cylinder 1024, and cannot be booted from\n");
203		}
204		i++;
205	}
206	if (i > 7) {
207		sprintf(msg+strlen(msg),
208		    "Max seven partitions per freebsd slice\n");
209	}
210	if (k > 1) {
211		sprintf(msg+strlen(msg),
212		    "Max one root partition child per freebsd slice\n");
213	}
214}
215
216void
217Check_Chunk(struct disk *d, struct chunk *c, char *msg)
218{
219	Rule_000(d,c,msg);
220	Rule_001(d,c,msg);
221	Rule_002(d,c,msg);
222	Rule_003(d,c,msg);
223	Rule_004(d,c,msg);
224	if (c->part)
225		Check_Chunk(d,c->part,msg);
226	if (c->next)
227		Check_Chunk(d,c->next,msg);
228
229	if (c->end >= 1024*d->bios_hd*d->bios_sect)
230		c->flags |= CHUNK_PAST_1024;
231	else
232		c->flags &= ~CHUNK_PAST_1024;
233}
234
235char *
236CheckRules(struct disk *d)
237{
238	char msg[BUFSIZ];
239
240	*msg = '\0';
241	Check_Chunk(d,d->chunks,msg);
242	if (*msg)
243		return strdup(msg);
244	return 0;
245}
246
247char *
248ChunkCanBeRoot(struct chunk *c)
249{
250	struct chunk *c1;
251	struct disk *d = c->disk;
252	char msg[BUFSIZ];
253
254	*msg = '\0';
255	if (c->flags & CHUNK_PAST_1024) {
256		strcat(msg,
257"The root partition must end before cylinder 1024 seen from\n");
258		strcat(msg,
259"the BIOS' point of view, or it cannot be booted from.\n");
260		return strdup(msg);
261	}
262	for (c1=d->chunks->part;;) {
263		for (; c1; c1=c1->next)
264			if (c1->offset <= c->offset && c1->end >= c->end)
265				break;
266		if (!c1) {
267			strcat(msg,
268"Internal trouble, cannot find this chunk in the chunk-tree\n");
269			return strdup(msg);
270		}
271		if (c1->type == freebsd)
272			break;
273		c1 = c1->part;
274	}
275
276	if (c1->type != freebsd) {
277		strcat(msg,
278"The root partition must be in a FreeBSD slice, otherwise\n");
279		strcat(msg,
280"the kernel cannot be booted from it\n");
281		return strdup(msg);
282	}
283
284	return NULL;
285}
286