xref: /minix3/usr.sbin/installboot/minixfs3.c (revision f14fb602092e015ff630df58e17c2a9cd57d29b3)
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