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