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 <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 static int minixfs3_read_mbr(const char* device, char* buf) 20 { 21 int fd; 22 int bytes; 23 int n; 24 25 fd = open(device, O_RDONLY); 26 if (fd == -1) { 27 fprintf(stderr, "Can't open %s: %s\n", device, strerror(errno)); 28 return 1; 29 } 30 31 if (lseek(fd, MBR_PART_OFFSET, SEEK_SET) != MBR_PART_OFFSET) { 32 fprintf(stderr, "Can't seek in %s to %d: %s\n", 33 device, MBR_PART_OFFSET, strerror(errno)); 34 close(fd); 35 return 1; 36 } 37 38 bytes = DFL_SECSIZE - MBR_PART_OFFSET; 39 40 if ((n = read(fd, buf, bytes)) != bytes) { 41 fprintf(stderr, "Can't read %d bytes from %s, %d read instead" 42 ": %s\n", 43 bytes, device, n, strerror(errno)); 44 close(fd); 45 return 1; 46 } 47 48 if ((uint8_t)buf[bytes-2] != 0x55 || (uint8_t)buf[bytes-1] != 0xAA) { 49 fprintf(stderr, "No MBR on %s, signature is %x\n", 50 device, *(uint16_t*)(&buf[bytes-2])); 51 close(fd); 52 return 1; 53 } 54 55 close(fd); 56 return 0; 57 } 58 59 60 int minixfs3_is_minix_partition(const char* partition) 61 { 62 char buf[DFL_SECSIZE]; /* part table + signature */ 63 int name_length = strlen(partition); 64 65 /* partition must be 0-3 */ 66 if (atol(&partition[name_length-1]) >= 4) { 67 fprintf(stderr, "Wrong device %s, must be /.../cxdyp[0-3]\n", 68 partition); 69 return 0; 70 } 71 72 /* it should be partition device, not disk */ 73 if (partition[name_length-2] != 'p') { 74 fprintf(stderr, "Wrong device %s, must be /.../cxdyp[0-3]\n", 75 partition); 76 return 0; 77 } 78 79 /* MINIX 3 partition with current scheme *must* have subpartitions, 80 * thus MBR has signature. minixfs3_read_mbr checks the signature. 81 */ 82 if (minixfs3_read_mbr(partition, buf)) 83 return 0; 84 return 1; 85 } 86 87 /* bootxx from NetBSD is ~8Kb, and old MINIX installations have just 88 * 1Kb of space for their bootblock. Check if there is enough space 89 * to install bootxx_minixfs3. New installation should have 16Kb before 90 * the first subpartition. 91 */ 92 int minixfs3_has_bootblock_space(const char* partition) 93 { 94 char buf[DFL_SECSIZE]; /* part table + signature */ 95 char disk[NAME_MAX]; 96 struct mbr_partition *part; 97 uint32_t first_subpartition = (uint32_t) ~0; 98 uint32_t parent_partition = 0; 99 int i; 100 int name_length = strlen(partition); 101 102 /* partition must be 0-3 */ 103 if (atol(&partition[name_length-1]) >= 4) { 104 fprintf(stderr, "Wrong device %s, must be /.../cxdyp[0-3]\n", 105 partition); 106 exit(1); 107 } 108 /* it should be partition device, not disk */ 109 if (partition[name_length-2] != 'p') { 110 fprintf(stderr, "Wrong device %s, must be /.../cxdyp[0-3]\n", 111 partition); 112 exit(1); 113 } 114 115 if (minixfs3_read_mbr(partition, buf)) 116 exit(1); 117 118 part = (struct mbr_partition *) buf; 119 120 for (i = 0; i < 4; i++) { 121 if (part[i].mbrp_size && part[i].mbrp_start < first_subpartition) 122 first_subpartition = part[i].mbrp_start; 123 } 124 125 strncpy(disk, partition, name_length - 2); 126 disk[name_length - 2] = '\0'; 127 128 if (minixfs3_read_mbr(disk, buf)) 129 exit(1); 130 131 for (i = 0; i < 4; i++) { 132 struct mbr_partition *p = &part[i]; 133 if (p->mbrp_size && p->mbrp_start <= first_subpartition 134 && (p->mbrp_start + p->mbrp_size) > first_subpartition) { 135 parent_partition = p->mbrp_start; 136 break; 137 } 138 } 139 140 if ((first_subpartition - parent_partition) < MFS_FIRST_SUBP_OFFSET) 141 return 0; 142 else 143 return 1; 144 } 145