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