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