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