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