rules.c revision 63030
11558Srgrimes/*
21558Srgrimes * ----------------------------------------------------------------------------
31558Srgrimes * "THE BEER-WARE LICENSE" (Revision 42):
41558Srgrimes * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
51558Srgrimes * can do whatever you want with this stuff. If we meet some day, and you think
61558Srgrimes * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
71558Srgrimes * ----------------------------------------------------------------------------
81558Srgrimes *
91558Srgrimes * $FreeBSD: head/lib/libdisk/rules.c 63030 2000-07-12 18:05:18Z jhb $
101558Srgrimes *
111558Srgrimes */
121558Srgrimes
131558Srgrimes#include <stdio.h>
141558Srgrimes#include <stdlib.h>
151558Srgrimes#include <unistd.h>
161558Srgrimes#include <string.h>
171558Srgrimes#include <sys/types.h>
181558Srgrimes#include <sys/diskslice.h>
191558Srgrimes#include <sys/disklabel.h>
201558Srgrimes#include <err.h>
211558Srgrimes#include "libdisk.h"
221558Srgrimes
231558Srgrimesint
241558SrgrimesTrack_Aligned(struct disk *d, u_long offset)
251558Srgrimes{
261558Srgrimes	if (!d->bios_sect)
271558Srgrimes		return 1;
281558Srgrimes	if (offset % d->bios_sect)
291558Srgrimes		return 0;
301558Srgrimes	return 1;
3136997Scharnier}
321558Srgrimes
3336997Scharnieru_long
3436997ScharnierPrev_Track_Aligned(struct disk *d, u_long offset)
3550476Speter{
361558Srgrimes	if (!d->bios_sect)
371558Srgrimes		return offset;
381558Srgrimes	return (offset / d->bios_sect) * d->bios_sect;
3971787Sphk}
401558Srgrimes
411558Srgrimesu_long
4298542SmckusickNext_Track_Aligned(struct disk *d, u_long offset)
4398542Smckusick{
441558Srgrimes	if (!d->bios_sect)
451558Srgrimes		return offset;
461558Srgrimes	return Prev_Track_Aligned(d,offset + d->bios_sect-1);
47103949Smike}
481558Srgrimes
491558Srgrimesint
501558SrgrimesCyl_Aligned(struct disk *d, u_long offset)
511558Srgrimes{
5290742Siedowse	if (!d->bios_sect || !d->bios_hd)
53217769Smckusick		return 1;
541558Srgrimes	if (offset % (d->bios_sect * d->bios_hd))
551558Srgrimes		return 0;
561558Srgrimes	return 1;
571558Srgrimes}
581558Srgrimes
5992837Simpu_long
6092837SimpPrev_Cyl_Aligned(struct disk *d, u_long offset)
611558Srgrimes{
621558Srgrimes	if (!d->bios_sect || !d->bios_hd)
631558Srgrimes		return offset;
641558Srgrimes	return (offset / (d->bios_sect*d->bios_hd)) * d->bios_sect * d->bios_hd;
651558Srgrimes}
661558Srgrimes
671558Srgrimesu_long
681558SrgrimesNext_Cyl_Aligned(struct disk *d, u_long offset)
691558Srgrimes{
701558Srgrimes	if (!d->bios_sect || !d->bios_hd)
711558Srgrimes		return offset;
721558Srgrimes	return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd)-1);
731558Srgrimes}
7492837Simp
751558Srgrimes/*
761558Srgrimes *  Rule#0:
7792837Simp *	Chunks of type 'whole' can have max NDOSPART children.
781558Srgrimes *	Only one of them can have the "active" flag
791558Srgrimes */
801558Srgrimesvoid
811558SrgrimesRule_000(struct disk *d, struct chunk *c, char *msg)
821558Srgrimes{
831558Srgrimes#ifdef PC98
841558Srgrimes	int i=0;
851558Srgrimes#else
861558Srgrimes	int i=0,j=0;
8792837Simp#endif
881558Srgrimes	struct chunk *c1;
891558Srgrimes
901558Srgrimes	if (c->type != whole)
911558Srgrimes		return;
921558Srgrimes	for (c1=c->part; c1; c1=c1->next) {
931558Srgrimes		if (c1->type != unused) continue;
941558Srgrimes#ifndef PC98
951558Srgrimes		if (c1->flags & CHUNK_ACTIVE)
961558Srgrimes			j++;
971558Srgrimes#endif
981558Srgrimes		i++;
991558Srgrimes	}
1001558Srgrimes	if (i > NDOSPART)
1011558Srgrimes		sprintf(msg+strlen(msg),
1021558Srgrimes	"%d is too many children of the 'whole' chunk.  Max is %d\n",
1031558Srgrimes			i, NDOSPART);
1041558Srgrimes#ifndef PC98
1051558Srgrimes	if (j > 1)
1061558Srgrimes		sprintf(msg+strlen(msg),
1071558Srgrimes	"Too many active children of 'whole'");
1081558Srgrimes#endif
1091558Srgrimes}
1101558Srgrimes
1111558Srgrimes/*
1121558Srgrimes * Rule#1:
1131558Srgrimes *	All children of 'whole' and 'extended'  must be track-aligned.
1141558Srgrimes *	Exception: the end can be unaligned if it matches the end of 'whole'
1151558Srgrimes */
1161558Srgrimesvoid
11783083SruRule_001(struct disk *d, struct chunk *c, char *msg)
1181558Srgrimes{
1191558Srgrimes	int i;
1201558Srgrimes	struct chunk *c1;
1211558Srgrimes
1221558Srgrimes	if (c->type != whole && c->type != extended)
1231558Srgrimes		return;
12492837Simp	for (i=0, c1=c->part; c1; c1=c1->next) {
1251558Srgrimes		if (c1->type == unused) continue;
1261558Srgrimes		c1->flags |= CHUNK_ALIGN;
1271558Srgrimes#ifdef PC98
1281558Srgrimes		if (!Cyl_Aligned(d,c1->offset))
1291558Srgrimes#else
1301558Srgrimes		if (!Track_Aligned(d,c1->offset))
1311558Srgrimes#endif
13271750Sphk			sprintf(msg+strlen(msg),
1331558Srgrimes#ifdef PC98
1341558Srgrimes		    "chunk '%s' [%ld..%ld] does not start on a cylinder boundary\n",
1351558Srgrimes#else
1361558Srgrimes		    "chunk '%s' [%ld..%ld] does not start on a track boundary\n",
1371558Srgrimes#endif
1381558Srgrimes				c1->name,c1->offset,c1->end);
1391558Srgrimes		if ((c->type == whole || c->end == c1->end)
1401558Srgrimes		    || Cyl_Aligned(d,c1->end+1))
1411558Srgrimes			;
1421558Srgrimes		else
1431558Srgrimes			sprintf(msg+strlen(msg),
1441558Srgrimes		    "chunk '%s' [%ld..%ld] does not end on a cylinder boundary\n",
1451558Srgrimes				c1->name,c1->offset,c1->end);
1461558Srgrimes	}
1471558Srgrimes}
1481558Srgrimes
1491558Srgrimes/*
15092837Simp * Rule#2:
1511558Srgrimes *	Max one 'fat' as child of 'whole'
1521558Srgrimes */
1531558Srgrimesvoid
1541558SrgrimesRule_002(struct disk *d, struct chunk *c, char *msg)
1551558Srgrimes{
1561558Srgrimes#ifndef PC98
1571558Srgrimes	int i;
15883083Sru	struct chunk *c1;
1591558Srgrimes
1601558Srgrimes	if (c->type != whole)
16192837Simp		return;
1621558Srgrimes	for (i=0, c1=c->part; c1; c1=c1->next) {
16383083Sru		if (c1->type != fat)
16483083Sru			continue;
1651558Srgrimes		i++;
16683083Sru	}
1671558Srgrimes	if (i > 1) {
1681558Srgrimes		sprintf(msg+strlen(msg),
16983083Sru		    "Max one 'fat' allowed as child of 'whole'\n");
17083083Sru	}
1711558Srgrimes#endif
1721558Srgrimes}
17383083Sru
17483083Sru/*
17583083Sru * Rule#3:
17683083Sru *	Max one extended as child of 'whole'
17783083Sru */
1781558Srgrimesvoid
17983083SruRule_003(struct disk *d, struct chunk *c, char *msg)
1801558Srgrimes{
1811558Srgrimes#ifndef PC98
1821558Srgrimes	int i;
18383083Sru	struct chunk *c1;
1841558Srgrimes
1851558Srgrimes	if (c->type != whole)
1861558Srgrimes		return;
1871558Srgrimes	for (i=0, c1=c->part; c1; c1=c1->next) {
1881558Srgrimes		if (c1->type != extended)
18992837Simp			continue;
1901558Srgrimes		i++;
19190743Siedowse	}
192129556Simp	if (i > 1) {
193161000Srse		sprintf(msg+strlen(msg),
19490743Siedowse		    "Max one 'extended' allowed as child of 'whole'\n");
1951558Srgrimes	}
196130753Siedowse#endif
197129556Simp}
198129556Simp
199130753Siedowse/*
200130753Siedowse * Rule#4:
201130753Siedowse *	Max seven 'part' as children of 'freebsd'
202130753Siedowse *	Max one CHUNK_IS_ROOT child per 'freebsd'
203129556Simp */
204129556Simpvoid
205129556SimpRule_004(struct disk *d, struct chunk *c, char *msg)
206129556Simp{
207129556Simp	int i=0,k=0;
208129556Simp	struct chunk *c1;
209129556Simp
21090743Siedowse	if (c->type != freebsd)
211161000Srse		return;
212161025Smarck
213129556Simp	for (c1=c->part; c1; c1=c1->next) {
214161017Smarck		if (c1->type != part)
215161017Smarck			continue;
216129556Simp		if (c1->flags & CHUNK_IS_ROOT)
217129556Simp			k++;
218129556Simp		i++;
219129556Simp	}
220161017Smarck	if (i > 7) {
221161000Srse		sprintf(msg+strlen(msg),
222129556Simp		    "Max seven partitions per freebsd slice\n");
2231558Srgrimes	}
2241558Srgrimes	if (k > 1) {
2251558Srgrimes		sprintf(msg+strlen(msg),
22690742Siedowse		    "Max one root partition child per freebsd slice\n");
22790742Siedowse	}
22890742Siedowse}
2291558Srgrimes
23092837Simpvoid
23190742SiedowseCheck_Chunk(struct disk *d, struct chunk *c, char *msg)
23290742Siedowse{
23390742Siedowse	Rule_000(d,c,msg);
23490742Siedowse	Rule_001(d,c,msg);
23590742Siedowse	Rule_002(d,c,msg);
2361558Srgrimes	Rule_003(d,c,msg);
2371558Srgrimes	Rule_004(d,c,msg);
2381558Srgrimes	if (c->part)
2391558Srgrimes		Check_Chunk(d,c->part,msg);
2401558Srgrimes	if (c->next)
2411558Srgrimes		Check_Chunk(d,c->next,msg);
2421558Srgrimes}
2431558Srgrimes
2441558Srgrimeschar *
245120323SpsCheckRules(struct disk *d)
246141965Sobrien{
2471558Srgrimes	char msg[BUFSIZ];
2481558Srgrimes
249139422Sobrien	*msg = '\0';
250139422Sobrien	Check_Chunk(d,d->chunks,msg);
251139422Sobrien	if (*msg)
2521558Srgrimes		return strdup(msg);
2531558Srgrimes	return 0;
2541558Srgrimes}
2551558Srgrimes
2561558Srgrimeschar *
2571558SrgrimesChunkCanBeRoot(struct chunk *c)
258141965Sobrien{
2591558Srgrimes	struct chunk *c1;
2601558Srgrimes	struct disk *d = c->disk;
2611558Srgrimes	char msg[BUFSIZ];
2621558Srgrimes
2631558Srgrimes	*msg = '\0';
2641558Srgrimes	for (c1=d->chunks->part;;) {
2651558Srgrimes		for (; c1; c1=c1->next)
2661558Srgrimes			if (c1->offset <= c->offset && c1->end >= c->end)
2671558Srgrimes				break;
2681558Srgrimes		if (!c1) {
2691558Srgrimes			strcat(msg,
2701558Srgrimes"Internal trouble, cannot find this chunk in the chunk-tree\n");
2711558Srgrimes			return strdup(msg);
2721558Srgrimes		}
2731558Srgrimes		if (c1->type == freebsd)
2741558Srgrimes			break;
2751558Srgrimes		c1 = c1->part;
2761558Srgrimes	}
2771558Srgrimes
2781558Srgrimes#ifndef PC98
2791558Srgrimes	if (c1->type != freebsd) {
2801558Srgrimes		strcat(msg,
2811558Srgrimes"The root partition must be in a FreeBSD slice, otherwise\n");
2821558Srgrimes		strcat(msg,
2831558Srgrimes"the kernel cannot be booted from it\n");
2841558Srgrimes		return strdup(msg);
2851558Srgrimes	}
2861558Srgrimes#endif
28792837Simp
2881558Srgrimes	return NULL;
28986473Siedowse}
2901558Srgrimes