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