1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdint.h> 4 #include <errno.h> 5 #include <sys/stat.h> 6 #include <limits.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 #include <string.h> 10 11 #include "installboot.h" 12 13 #ifndef DFL_SECSIZE 14 #define DFL_SECSIZE 512 15 #endif 16 17 #define MFS_FIRST_SUBP_OFFSET 32 18 19 enum { 20 TYPE_BAD, 21 TYPE_PART, 22 TYPE_DISK 23 }; 24 25 static int 26 minixfs3_read_mbr(const char* device, char* buf) 27 { 28 int fd; 29 int bytes; 30 int n; 31 32 fd = open(device, O_RDONLY); 33 if (fd == -1) { 34 fprintf(stderr, "Can't open %s: %s\n", device, strerror(errno)); 35 return 1; 36 } 37 38 if (lseek(fd, MBR_PART_OFFSET, SEEK_SET) != MBR_PART_OFFSET) { 39 fprintf(stderr, "Can't seek in %s to %d: %s\n", 40 device, MBR_PART_OFFSET, strerror(errno)); 41 close(fd); 42 return 1; 43 } 44 45 bytes = DFL_SECSIZE - MBR_PART_OFFSET; 46 47 if ((n = read(fd, buf, bytes)) != bytes) { 48 fprintf(stderr, "Can't read %d bytes from %s, %d read instead" 49 ": %s\n", 50 bytes, device, n, strerror(errno)); 51 close(fd); 52 return 1; 53 } 54 55 if ((uint8_t)buf[bytes-2] != 0x55 || (uint8_t)buf[bytes-1] != 0xAA) { 56 fprintf(stderr, "No MBR on %s, signature is %x\n", 57 device, *(uint16_t*)(&buf[bytes-2])); 58 close(fd); 59 return 1; 60 } 61 62 close(fd); 63 return 0; 64 } 65 66 static int 67 minixfs3_get_dev_type(const char *device, ib_params *params) 68 { 69 int len, type; 70 71 /* 72 * Unless the -f flag is given, we expect to be provided with a primary 73 * partition. That is, a device name that ends with "pN", N being 0-3. 74 * If the -f flag is given, we assume that anything else is a whole 75 * disk. If we were given a subpartition, it will fail the subsequent 76 * MBR signature test, so we need not check this explicitly. 77 */ 78 len = strlen(device); 79 80 if (len > 2 && device[len-2] == 'p' && 81 (unsigned) (device[len-1] - '0') <= 3) { 82 type = TYPE_PART; 83 } else { 84 type = TYPE_DISK; 85 } 86 87 if (type != TYPE_PART && !(params->flags & IB_FORCE)) { 88 fprintf(stderr, "Wrong device %s, must be /.../cxdyp[0-3]\n", 89 device); 90 return TYPE_BAD; 91 } 92 93 return type; 94 } 95 96 int 97 minixfs3_is_minix_partition(ib_params *params) 98 { 99 char buf[DFL_SECSIZE]; /* part table + signature */ 100 101 if (minixfs3_get_dev_type(params->filesystem, params) == TYPE_BAD) 102 return 0; 103 104 /* MINIX 3 partition with current scheme *must* have subpartitions, 105 * thus MBR has signature. minixfs3_read_mbr checks the signature. 106 */ 107 if (minixfs3_read_mbr(params->filesystem, buf)) 108 return 0; 109 return 1; 110 } 111 112 /* bootxx from NetBSD is ~8Kb, and old MINIX installations have just 113 * 1Kb of space for their bootblock. Check if there is enough space 114 * to install bootxx_minixfs3. New installation should have 16Kb before 115 * the first subpartition. 116 */ 117 int 118 minixfs3_has_bootblock_space(ib_params *params) 119 { 120 const char *device; 121 char buf[DFL_SECSIZE]; /* part table + signature */ 122 char parent_name[NAME_MAX]; 123 struct mbr_partition *part; 124 uint32_t first_subpartition = (uint32_t) ~0; 125 uint32_t parent_partition; 126 int i, len, type = 0; 127 128 device = params->filesystem; 129 130 if ((type = minixfs3_get_dev_type(device, params)) == TYPE_BAD) 131 exit(1); 132 133 if (minixfs3_read_mbr(device, buf)) 134 exit(1); 135 136 part = (struct mbr_partition *) buf; 137 138 for (i = 0; i < 4; i++) { 139 if (part[i].mbrp_size && 140 part[i].mbrp_start < first_subpartition) 141 first_subpartition = part[i].mbrp_start; 142 } 143 144 if (type == TYPE_PART) { 145 /* The target is a partition. Look up its starting offset. */ 146 len = strlen(device); 147 strncpy(parent_name, device, len - 2); 148 parent_name[len - 2] = '\0'; 149 150 if (minixfs3_read_mbr(parent_name, buf)) 151 exit(1); 152 153 parent_partition = 0; 154 for (i = 0; i < 4; i++) { 155 struct mbr_partition *p = &part[i]; 156 if (p->mbrp_size && p->mbrp_start <= first_subpartition 157 && (p->mbrp_start + p->mbrp_size) > 158 first_subpartition) { 159 parent_partition = p->mbrp_start; 160 break; 161 } 162 } 163 } else { 164 /* The target is a whole disk. The starting offset is 0. */ 165 parent_partition = 0; 166 } 167 168 if ((first_subpartition - parent_partition) < MFS_FIRST_SUBP_OFFSET) 169 return 0; 170 else 171 return 1; 172 } 173