1/* 2 * ptgen - partition table generator 3 * Copyright (C) 2006 by Felix Fietkau <nbd@openwrt.org> 4 * 5 * uses parts of afdisk 6 * Copyright (C) 2002 by David Roetzel <david@roetzel.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include <sys/types.h> 24#include <sys/stat.h> 25#include <string.h> 26#include <unistd.h> 27#include <stdlib.h> 28#include <stdio.h> 29#include <ctype.h> 30#include <fcntl.h> 31 32#if __BYTE_ORDER == __BIG_ENDIAN 33#define cpu_to_le16(x) bswap_16(x) 34#elif __BYTE_ORDER == __LITTLE_ENDIAN 35#define cpu_to_le16(x) (x) 36#else 37#error unknown endianness! 38#endif 39 40/* Partition table entry */ 41struct pte { 42 unsigned char active; 43 unsigned char chs_start[3]; 44 unsigned char type; 45 unsigned char chs_end[3]; 46 unsigned int start; 47 unsigned int length; 48}; 49 50struct partinfo { 51 unsigned long size; 52 int type; 53}; 54 55int verbose = 0; 56int active = 1; 57int heads = -1; 58int sectors = -1; 59int kb_align = 0; 60struct partinfo parts[4]; 61char *filename = NULL; 62 63 64/* 65 * parse the size argument, which is either 66 * a simple number (K assumed) or 67 * K, M or G 68 * 69 * returns the size in KByte 70 */ 71static long to_kbytes(const char *string) { 72 int exp = 0; 73 long result; 74 char *end; 75 76 result = strtoul(string, &end, 0); 77 switch (tolower(*end)) { 78 case 'k' : 79 case '\0' : exp = 0; break; 80 case 'm' : exp = 1; break; 81 case 'g' : exp = 2; break; 82 default: return 0; 83 } 84 85 if (*end) 86 end++; 87 88 if (*end) { 89 fprintf(stderr, "garbage after end of number\n"); 90 return 0; 91 } 92 93 /* result: number + 1024^(exp) */ 94 return result * ((2 << ((10 * exp) - 1)) ?: 1); 95} 96 97/* convert the sector number into a CHS value for the partition table */ 98static void to_chs(long sect, unsigned char chs[3]) { 99 int c,h,s; 100 101 s = (sect % sectors) + 1; 102 sect = sect / sectors; 103 h = sect % heads; 104 sect = sect / heads; 105 c = sect; 106 107 chs[0] = h; 108 chs[1] = s | ((c >> 2) & 0xC0); 109 chs[2] = c & 0xFF; 110 111 return; 112} 113 114/* round the sector number up to the next cylinder */ 115static inline unsigned long round_to_cyl(long sect) { 116 int cyl_size = heads * sectors; 117 118 return sect + cyl_size - (sect % cyl_size); 119} 120 121/* round the sector number up to the kb_align boundary */ 122static inline unsigned long round_to_kb(long sect) { 123 return ((sect - 1) / kb_align + 1) * kb_align; 124} 125 126/* check the partition sizes and write the partition table */ 127static int gen_ptable(int nr) 128{ 129 struct pte pte[4]; 130 unsigned long sect = 0; 131 int i, fd, ret = -1, start, len; 132 133 memset(pte, 0, sizeof(struct pte) * 4); 134 for (i = 0; i < nr; i++) { 135 if (!parts[i].size) { 136 fprintf(stderr, "Invalid size in partition %d!\n", i); 137 return -1; 138 } 139 pte[i].active = ((i + 1) == active) ? 0x80 : 0; 140 pte[i].type = parts[i].type; 141 start = sect + sectors; 142 if (kb_align != 0) 143 start = round_to_kb(start); 144 pte[i].start = cpu_to_le16(start); 145 sect = start + parts[i].size * 2; 146 if (kb_align == 0) 147 sect = round_to_cyl(sect); 148 pte[i].length = cpu_to_le16(len = sect - start); 149 to_chs(start, pte[i].chs_start); 150 to_chs(start + len - 1, pte[i].chs_end); 151 if (verbose) 152 fprintf(stderr, "Partition %d: start=%ld, end=%ld, size=%ld\n", i, (long) start * 512, ((long) start + (long) len) * 512, (long) len * 512); 153 printf("%ld\n", ((long) start * 512)); 154 printf("%ld\n", ((long) len * 512)); 155 } 156 157 if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { 158 fprintf(stderr, "Can't open output file '%s'\n",filename); 159 return -1; 160 } 161 162 lseek(fd, 446, SEEK_SET); 163 if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) { 164 fprintf(stderr, "write failed.\n"); 165 goto fail; 166 } 167 lseek(fd, 510, SEEK_SET); 168 if (write(fd, "\x55\xaa", 2) != 2) { 169 fprintf(stderr, "write failed.\n"); 170 goto fail; 171 } 172 173 ret = 0; 174fail: 175 close(fd); 176 return ret; 177} 178 179static void usage(char *prog) 180{ 181 fprintf(stderr, "Usage: %s [-v] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [[-t <type>] -p <size>...] \n", prog); 182 exit(1); 183} 184 185int main (int argc, char **argv) 186{ 187 char type = 0x83; 188 int ch; 189 int part = 0; 190 191 while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vl:")) != -1) { 192 switch (ch) { 193 case 'o': 194 filename = optarg; 195 break; 196 case 'v': 197 verbose++; 198 break; 199 case 'h': 200 heads = (int) strtoul(optarg, NULL, 0); 201 break; 202 case 's': 203 sectors = (int) strtoul(optarg, NULL, 0); 204 break; 205 case 'p': 206 if (part > 3) { 207 fprintf(stderr, "Too many partitions\n"); 208 exit(1); 209 } 210 parts[part].size = to_kbytes(optarg); 211 parts[part++].type = type; 212 break; 213 case 't': 214 type = (char) strtoul(optarg, NULL, 16); 215 break; 216 case 'a': 217 active = (int) strtoul(optarg, NULL, 0); 218 if ((active < 0) || (active > 4)) 219 active = 0; 220 break; 221 case 'l': 222 kb_align = (int) strtoul(optarg, NULL, 0) * 2; 223 break; 224 case '?': 225 default: 226 usage(argv[0]); 227 } 228 } 229 argc -= optind; 230 if (argc || (heads <= 0) || (sectors <= 0) || !filename) 231 usage(argv[0]); 232 233 return gen_ptable(part); 234} 235