rules.c revision 104674
175584Sru/*
275584Sru * ----------------------------------------------------------------------------
375584Sru * "THE BEER-WARE LICENSE" (Revision 42):
4104862Sru * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
575584Sru * can do whatever you want with this stuff. If we meet some day, and you think
675584Sru * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
775584Sru * ----------------------------------------------------------------------------
875584Sru */
975584Sru
1075584Sru#include <sys/cdefs.h>
1175584Sru__FBSDID("$FreeBSD: head/lib/libdisk/rules.c 104674 2002-10-08 12:13:19Z nyan $");
1275584Sru
1375584Sru#include <stdio.h>
1475584Sru#include <stdlib.h>
1575584Sru#include <unistd.h>
1675584Sru#include <string.h>
1775584Sru#include <sys/types.h>
1875584Sru#include <sys/diskslice.h>
1975584Sru#include <sys/disklabel.h>
2075584Sru#ifdef PC98
2175584Sru#include <sys/diskpc98.h>
2275584Sru#else
2375584Sru#include <sys/diskmbr.h>
2475584Sru#endif
2575584Sru#include "libdisk.h"
2675584Sru
2775584Sruint
2875584SruTrack_Aligned(struct disk *d, u_long offset)
2975584Sru{
3075584Sru	if (!d->bios_sect)
3175584Sru		return 1;
3275584Sru	if (offset % d->bios_sect)
3375584Sru		return 0;
3475584Sru	return 1;
3575584Sru}
3675584Sru
3775584Sruu_long
3875584SruPrev_Track_Aligned(struct disk *d, u_long offset)
3975584Sru{
4075584Sru	if (!d->bios_sect)
4175584Sru		return offset;
4275584Sru	return (offset / d->bios_sect) * d->bios_sect;
4375584Sru}
4475584Sru
4575584Sruu_long
4675584SruNext_Track_Aligned(struct disk *d, u_long offset)
4775584Sru{
4875584Sru	if (!d->bios_sect)
4975584Sru		return offset;
5075584Sru	return Prev_Track_Aligned(d, offset + d->bios_sect-1);
5175584Sru}
5275584Sru
5375584Sruint
5475584SruCyl_Aligned(struct disk *d, u_long offset)
5575584Sru{
5675584Sru	if (!d->bios_sect || !d->bios_hd)
5775584Sru		return 1;
5875584Sru	if (offset % (d->bios_sect * d->bios_hd))
5975584Sru		return 0;
6075584Sru	return 1;
6175584Sru}
6275584Sru
6375584Sruu_long
6475584SruPrev_Cyl_Aligned(struct disk *d, u_long offset)
6575584Sru{
6675584Sru	if (!d->bios_sect || !d->bios_hd)
6775584Sru		return offset;
6875584Sru	return (offset / (d->bios_sect*d->bios_hd)) * d->bios_sect * d->bios_hd;
6975584Sru}
7075584Sru
7175584Sruu_long
7275584SruNext_Cyl_Aligned(struct disk *d, u_long offset)
7375584Sru{
7475584Sru	if (!d->bios_sect || !d->bios_hd)
7575584Sru		return offset;
7675584Sru	return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd)-1);
7775584Sru}
7875584Sru
7975584Sru/*
80104862Sru *  Rule#0:
8175584Sru *	Chunks of type 'whole' can have max NDOSPART children.
8275584Sru *	Only one of them can have the "active" flag
8375584Sru */
8475584Sruvoid
8575584SruRule_000(struct disk *d, struct chunk *c, char *msg)
8675584Sru{
8775584Sru#ifdef PC98
8875584Sru	int i=0;
8975584Sru#else
9075584Sru	int i=0,j=0;
9175584Sru#endif
9275584Sru	struct chunk *c1;
9375584Sru
9475584Sru	if (c->type != whole)
9575584Sru		return;
9675584Sru	for (c1 = c->part; c1; c1 = c1->next) {
9775584Sru		if (c1->type != unused) continue;
9875584Sru#ifndef PC98
9975584Sru		if (c1->flags & CHUNK_ACTIVE)
10075584Sru			j++;
10175584Sru#endif
10275584Sru		i++;
10375584Sru	}
10475584Sru	if (i > NDOSPART)
10575584Sru		sprintf(msg + strlen(msg),
10675584Sru	"%d is too many children of the 'whole' chunk.  Max is %d\n",
10775584Sru			i, NDOSPART);
10875584Sru#ifndef PC98
10975584Sru	if (j > 1)
11075584Sru		sprintf(msg + strlen(msg),
11175584Sru	"Too many active children of 'whole'");
11275584Sru#endif
11375584Sru}
11475584Sru
11575584Sru/*
11675584Sru * Rule#1:
117104862Sru *	All children of 'whole' and 'extended'  must be track-aligned.
11875584Sru *	Exception: the end can be unaligned if it matches the end of 'whole'
11975584Sru */
12075584Sruvoid
12175584SruRule_001(struct disk *d, struct chunk *c, char *msg)
12275584Sru{
12375584Sru	int i;
12475584Sru	struct chunk *c1;
12575584Sru
12675584Sru	if (c->type != whole && c->type != extended)
12775584Sru		return;
12875584Sru	for (i = 0, c1 = c->part; c1; c1 = c1->next) {
129114402Sru		if (c1->type == unused) continue;
13075584Sru		c1->flags |= CHUNK_ALIGN;
13175584Sru#ifdef PC98
13275584Sru		if (!Cyl_Aligned(d, c1->offset))
13375584Sru#else
13475584Sru		if (!Track_Aligned(d, c1->offset))
135104862Sru#endif
13675584Sru			sprintf(msg + strlen(msg),
13775584Sru#ifdef PC98
13875584Sru		    "chunk '%s' [%ld..%ld] does not start on a cylinder boundary\n",
139104862Sru#else
14075584Sru		    "chunk '%s' [%ld..%ld] does not start on a track boundary\n",
14175584Sru#endif
14275584Sru				c1->name, c1->offset, c1->end);
14375584Sru		if ((c->type == whole || c->end == c1->end)
14475584Sru		    || Cyl_Aligned(d, c1->end + 1))
14575584Sru			;
14675584Sru		else
14775584Sru			sprintf(msg + strlen(msg),
14875584Sru		    "chunk '%s' [%ld..%ld] does not end on a cylinder boundary\n",
14975584Sru				c1->name, c1->offset, c1->end);
15075584Sru	}
15175584Sru}
15275584Sru
15375584Sru/*
15475584Sru * Rule#2:
15575584Sru *	Max one 'fat' as child of 'whole'
15675584Sru */
15775584Sruvoid
15875584SruRule_002(struct disk *d, struct chunk *c, char *msg)
15975584Sru{
16075584Sru#ifndef PC98
16175584Sru	int i;
16275584Sru	struct chunk *c1;
16375584Sru
16475584Sru	if (c->type != whole)
16575584Sru		return;
16675584Sru	for (i = 0, c1 = c->part; c1; c1 = c1->next) {
16775584Sru		if (c1->type != fat)
16875584Sru			continue;
16975584Sru		i++;
17075584Sru	}
17175584Sru	if (i > 1) {
17275584Sru		sprintf(msg + strlen(msg),
173104862Sru		    "Max one 'fat' allowed as child of 'whole'\n");
17475584Sru	}
17575584Sru#endif
17675584Sru}
17775584Sru
17875584Sru/*
17975584Sru * Rule#3:
18075584Sru *	Max one extended as child of 'whole'
18175584Sru */
18275584Sruvoid
18375584SruRule_003(struct disk *d, struct chunk *c, char *msg)
18475584Sru{
18575584Sru#ifndef PC98
18675584Sru	int i;
18775584Sru	struct chunk *c1;
18875584Sru
18975584Sru	if (c->type != whole)
19075584Sru		return;
19175584Sru	for (i = 0, c1 = c->part; c1; c1 = c1->next) {
19275584Sru		if (c1->type != extended)
19375584Sru			continue;
19475584Sru		i++;
19575584Sru	}
19675584Sru	if (i > 1) {
19775584Sru		sprintf(msg + strlen(msg),
19875584Sru		    "Max one 'extended' allowed as child of 'whole'\n");
19975584Sru	}
20075584Sru#endif
20175584Sru}
20275584Sru
20375584Sru/*
20475584Sru * Rule#4:
205104862Sru *	Max seven 'part' as children of 'freebsd'
20675584Sru *	Max one CHUNK_IS_ROOT child per 'freebsd'
20775584Sru */
20875584Sruvoid
20975584SruRule_004(struct disk *d, struct chunk *c, char *msg)
21075584Sru{
21175584Sru	int i=0,k=0;
21275584Sru	struct chunk *c1;
21375584Sru
214	if (c->type != freebsd)
215		return;
216
217	for (c1 = c->part; c1; c1 = c1->next) {
218		if (c1->type != part)
219			continue;
220		if (c1->flags & CHUNK_IS_ROOT)
221			k++;
222		i++;
223	}
224	if (i > 7) {
225		sprintf(msg + strlen(msg),
226		    "Max seven partitions per freebsd slice\n");
227	}
228	if (k > 1) {
229		sprintf(msg + strlen(msg),
230		    "Max one root partition child per freebsd slice\n");
231	}
232}
233
234void
235Check_Chunk(struct disk *d, struct chunk *c, char *msg)
236{
237	Rule_000(d, c, msg);
238	Rule_001(d, c, msg);
239	Rule_002(d, c, msg);
240	Rule_003(d, c, msg);
241	Rule_004(d, c, msg);
242	if (c->part)
243		Check_Chunk(d, c->part, msg);
244	if (c->next)
245		Check_Chunk(d, c->next, msg);
246}
247
248char *
249CheckRules(struct disk *d)
250{
251	char msg[BUFSIZ];
252
253	*msg = '\0';
254	Check_Chunk(d, d->chunks, msg);
255	if (*msg)
256		return strdup(msg);
257	return 0;
258}
259
260char *
261ChunkCanBeRoot(struct chunk *c)
262{
263	struct chunk *c1;
264	struct disk *d = c->disk;
265	char msg[BUFSIZ];
266
267	*msg = '\0';
268	for (c1 = d->chunks->part; ; ) {
269		for (; c1; c1 = c1->next)
270			if (c1->offset <= c->offset && c1->end >= c->end)
271				break;
272		if (!c1) {
273			strcat(msg,
274"Internal trouble, cannot find this chunk in the chunk-tree\n");
275			return strdup(msg);
276		}
277		if (c1->type == freebsd)
278			break;
279		c1 = c1->part;
280	}
281
282#ifndef PC98
283	if (c1->type != freebsd) {
284		strcat(msg,
285"The root partition must be in a FreeBSD slice, otherwise\n");
286		strcat(msg,
287"the kernel cannot be booted from it\n");
288		return strdup(msg);
289	}
290#endif
291
292	return NULL;
293}
294