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