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