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