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