1 /* repartition 1.18 - Load a partition table Author: Kees J. Bot 2 * 30 Nov 1991 3 */ 4 #define nil 0 5 #include <stdio.h> 6 #include <sys/types.h> 7 #include <sys/ioctl.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <fcntl.h> 11 #include <minix/config.h> 12 #include <minix/const.h> 13 #include <minix/partition.h> 14 #include <machine/partition.h> 15 #include <sys/stat.h> 16 #include <string.h> 17 #include <errno.h> 18 #include <dirent.h> 19 #include <limits.h> 20 21 #define DEV_FD0 0x200 22 23 #define SECTOR_SIZE 512 24 25 #define arraysize(a) (sizeof(a)/sizeof((a)[0])) 26 #define arraylimit(a) ((a) + arraysize(a)) 27 28 char *arg0; 29 char *dev_file; /* Device to repartition. */ 30 31 #ifndef S_ISLNK 32 /* There were no symlinks in medieval times. */ 33 #define lstat stat 34 #endif 35 36 void report(const char *label) 37 { 38 fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno)); 39 } 40 41 void fatal(const char *label) 42 { 43 report(label); 44 exit(1); 45 } 46 47 #define MINOR_d0p0s0 128 48 49 void partsort(struct part_entry *pe) 50 /* DOS has the misguided idea that partition tables must be sorted. */ 51 { 52 int i,j; 53 struct part_entry tmp; 54 55 for (i = 0; i < NR_PARTITIONS; i++) 56 for (j = 0; j < NR_PARTITIONS-1; j++) 57 if ((pe[j].sysind == NO_PART && pe[j+1].sysind != NO_PART) || 58 (pe[j].lowsec > pe[j+1].lowsec && pe[j+1].sysind != NO_PART)) { 59 tmp = pe[j]; 60 pe[j] = pe[j+1]; 61 pe[j+1] = tmp; 62 } 63 } 64 65 char *finddev(dev_t device) 66 /* Find the device next to dev_file with the given device number. */ 67 { 68 DIR *dp; 69 struct dirent *de; 70 static char name[PATH_MAX]; 71 char *np; 72 size_t nlen; 73 struct stat st; 74 75 if ((np= strrchr(dev_file, '/')) == nil) np= dev_file; else np++; 76 nlen= np - dev_file; 77 if (nlen > PATH_MAX - NAME_MAX - 1) { 78 fprintf(stderr, "%s: %s: Name is way too long\n", 79 arg0, dev_file); 80 exit(1); 81 } 82 memcpy(name, dev_file, nlen); 83 84 if ((dp= opendir("/dev")) == nil) fatal("/dev"); 85 while ((de= readdir(dp)) != nil) { 86 strcpy(name+nlen, de->d_name); 87 if (lstat(name, &st) == 0 88 && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) 89 && st.st_rdev == device 90 ) { 91 closedir(dp); 92 return name; 93 } 94 } 95 fprintf(stderr, "%s: Can't find partition devices associated with %s\n", 96 arg0, dev_file); 97 exit(1); 98 } 99 100 #define DSETP 0 101 #define DGETP 1 102 103 int diocntl(dev_t device, int request, struct part_geom *entry) 104 /* Get or set the geometry of a device. */ 105 { 106 char *name; 107 int r, f, err; 108 109 name= finddev(device); 110 if ((f= open(name, O_RDONLY)) < 0) return -1; 111 r= ioctl(f, request == DSETP ? DIOCSETP : DIOCGETP, (void *) entry); 112 err= errno; 113 (void) close(f); 114 errno= err; 115 return r; 116 } 117 118 struct part_geom geometry; /* Geometry of the device. */ 119 120 void print_chs(unsigned long sector) 121 { 122 unsigned secspcyl = geometry.heads * geometry.sectors; 123 int delta= 0; 124 125 if (sector == -1) { sector= 0; delta= -1; } 126 127 printf(" %5d/%03d/%02d", 128 (int) (sector / secspcyl), 129 (int) (sector % secspcyl) / geometry.sectors, 130 (int) (sector % geometry.sectors) + delta); 131 } 132 133 void show_part(char *name, unsigned long base, unsigned long size) 134 { 135 int i; 136 static int len= 0; 137 138 if (len == 0) { 139 len= strlen(name) + 3; 140 printf("device"); 141 for (i = 6; i < len; i++) fputc(' ', stdout); 142 printf( 143 " first last base size kb\n"); 144 } 145 146 printf("%s", name); 147 for (i = strlen(name); i < len; i++) fputc(' ', stdout); 148 149 print_chs(base); 150 print_chs(base + size - 1); 151 printf(" %9lu %9lu %9lu\n", base, size, size / (1024/SECTOR_SIZE)); 152 } 153 154 int main(int argc, char **argv) 155 { 156 struct stat hdst; 157 struct part_geom whole, entry; 158 struct part_entry table[4], *pe; 159 int drive, par = 0, device, incr; 160 int partf; 161 char *table_file; 162 int hd_major, hd_minor; 163 int needsort; 164 int shrink; /* True if partitions are shrinked to fit. */ 165 unsigned long base, size, limit; 166 167 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++; 168 169 if (argc < 2 || argc > 3) { 170 fprintf(stderr, 171 "Usage: %s device [partition-file]\n", arg0); 172 exit(1); 173 } 174 dev_file= argv[1]; 175 table_file= argv[argc - 1]; 176 shrink= (argc == 2); 177 178 if (stat(dev_file, &hdst) < 0) fatal(dev_file); 179 180 /* Geometry (to print nice numbers.) */ 181 if (diocntl(hdst.st_rdev, DGETP, &geometry) < 0) fatal(dev_file); 182 183 if (!S_ISBLK(hdst.st_mode)) { 184 fprintf(stderr, "%s: %s is not a device\n", arg0, dev_file); 185 exit(1); 186 } 187 hd_major= major(hdst.st_rdev); 188 hd_minor= minor(hdst.st_rdev); 189 190 if (hd_minor >= MINOR_d0p0s0) { 191 errno= EINVAL; 192 fatal(dev_file); 193 } 194 195 if (hd_major == major(DEV_FD0)) { 196 /* HD is actually a floppy. */ 197 if (hd_minor >= 4) { 198 errno= EINVAL; 199 fatal(dev_file); 200 } 201 device= hd_minor + (28 << 2); 202 incr= 4; 203 needsort= 0; 204 } else 205 if (hd_minor % (1 + NR_PARTITIONS) == 0) { 206 /* Partitioning hd0, hd5, ... */ 207 device= hd_minor + 1; 208 incr= 1; 209 needsort= 1; 210 } else { 211 /* Subpartitioning hd[1-4], hd[6-9], ... */ 212 drive= hd_minor / (1 + NR_PARTITIONS); 213 par= hd_minor % (1 + NR_PARTITIONS) - 1; 214 215 device= MINOR_d0p0s0 216 + (drive * NR_PARTITIONS + par) * NR_PARTITIONS; 217 if (device + NR_PARTITIONS - 1 > BYTE) { 218 errno= EINVAL; 219 fatal(dev_file); 220 } 221 incr= 1; 222 needsort= 0; 223 } 224 /* Device is now the first of the minor devices to be repartitioned. */ 225 226 /* Read the partition table from the boot block. */ 227 if ((partf= open(table_file, O_RDONLY)) < 0 228 || lseek(partf, (off_t) PART_TABLE_OFF, SEEK_SET) == -1 229 || (par= read(partf, (char *) table, (int) sizeof(table))) < 0 230 ) fatal(table_file); 231 232 if (par < sizeof(table)) { 233 fprintf(stderr, "%s: %s does not contain a partition table\n", 234 arg0, table_file); 235 exit(1); 236 } 237 if (needsort) partsort(table); 238 239 /* Show the geometry of the affected drive or partition. */ 240 if (diocntl(hdst.st_rdev, DGETP, &whole) < 0) fatal(dev_file); 241 242 /* Use sector numbers. */ 243 base = whole.base / SECTOR_SIZE; 244 size = whole.size / SECTOR_SIZE; 245 limit = base + size; 246 247 show_part(dev_file, base, size); 248 249 /* Send the partition table entries to the device driver. */ 250 for (par= 0; par < NR_PARTITIONS; par++, device+= incr) { 251 pe = &table[par]; 252 if (shrink && pe->size != 0) { 253 /* Shrink the partition entry to fit within the 254 * enclosing device just like the driver does. 255 */ 256 unsigned long part_limit= pe->lowsec + pe->size; 257 258 if (part_limit < pe->lowsec) part_limit= limit; 259 if (part_limit > limit) part_limit= limit; 260 if (pe->lowsec < base) pe->lowsec= base; 261 if (part_limit < pe->lowsec) part_limit= pe->lowsec; 262 pe->size= part_limit - pe->lowsec; 263 } 264 265 entry.base= (off_t)pe->lowsec * SECTOR_SIZE; 266 entry.size= (off_t)pe->size * SECTOR_SIZE; 267 if (diocntl(makedev(hd_major, device), DSETP, &entry) < 0) 268 fatal(dev_file); 269 270 show_part(finddev(makedev(hd_major, device)), 271 pe->lowsec, pe->size); 272 } 273 exit(0); 274 } 275