rules.c revision 104272
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: head/lib/libdisk/rules.c 104272 2002-10-01 07:24:55Z phk $");
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 <sys/diskmbr.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#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 */
116void
117Rule_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 */
153void
154Rule_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 */
178void
179Rule_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 */
204void
205Rule_004(struct disk *d, struct chunk *c, char *msg)
206{
207	int i=0,k=0;
208	struct chunk *c1;
209
210	if (c->type != freebsd)
211		return;
212
213	for (c1 = c->part; c1; c1 = c1->next) {
214		if (c1->type != part)
215			continue;
216		if (c1->flags & CHUNK_IS_ROOT)
217			k++;
218		i++;
219	}
220	if (i > 7) {
221		sprintf(msg + strlen(msg),
222		    "Max seven partitions per freebsd slice\n");
223	}
224	if (k > 1) {
225		sprintf(msg + strlen(msg),
226		    "Max one root partition child per freebsd slice\n");
227	}
228}
229
230void
231Check_Chunk(struct disk *d, struct chunk *c, char *msg)
232{
233	Rule_000(d, c, msg);
234	Rule_001(d, c, msg);
235	Rule_002(d, c, msg);
236	Rule_003(d, c, msg);
237	Rule_004(d, c, msg);
238	if (c->part)
239		Check_Chunk(d, c->part, msg);
240	if (c->next)
241		Check_Chunk(d, c->next, msg);
242}
243
244char *
245CheckRules(struct disk *d)
246{
247	char msg[BUFSIZ];
248
249	*msg = '\0';
250	Check_Chunk(d, d->chunks, msg);
251	if (*msg)
252		return strdup(msg);
253	return 0;
254}
255
256char *
257ChunkCanBeRoot(struct chunk *c)
258{
259	struct chunk *c1;
260	struct disk *d = c->disk;
261	char msg[BUFSIZ];
262
263	*msg = '\0';
264	for (c1 = d->chunks->part; ; ) {
265		for (; c1; c1 = c1->next)
266			if (c1->offset <= c->offset && c1->end >= c->end)
267				break;
268		if (!c1) {
269			strcat(msg,
270"Internal trouble, cannot find this chunk in the chunk-tree\n");
271			return strdup(msg);
272		}
273		if (c1->type == freebsd)
274			break;
275		c1 = c1->part;
276	}
277
278#ifndef PC98
279	if (c1->type != freebsd) {
280		strcat(msg,
281"The root partition must be in a FreeBSD slice, otherwise\n");
282		strcat(msg,
283"the kernel cannot be booted from it\n");
284		return strdup(msg);
285	}
286#endif
287
288	return NULL;
289}
290