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