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