xref: /minix3/usr.sbin/installboot/minixfs3.c (revision e70e5a17224e0cc1a08db48f20a568b951cd58c1)
1*e70e5a17SAntoine Leca #if HAVE_NBTOOL_CONFIG_H
2*e70e5a17SAntoine Leca #include "nbtool_config.h"
3*e70e5a17SAntoine Leca #endif
4*e70e5a17SAntoine Leca 
5fa6c4a25SEvgeniy Ivanov #include <stdio.h>
6fa6c4a25SEvgeniy Ivanov #include <stdlib.h>
7fa6c4a25SEvgeniy Ivanov #include <stdint.h>
8fa6c4a25SEvgeniy Ivanov #include <errno.h>
9fa6c4a25SEvgeniy Ivanov #include <sys/stat.h>
109af3a794SJean-Baptiste Boric #include <limits.h>
11fa6c4a25SEvgeniy Ivanov #include <fcntl.h>
12fa6c4a25SEvgeniy Ivanov #include <unistd.h>
13fa6c4a25SEvgeniy Ivanov #include <string.h>
14fa6c4a25SEvgeniy Ivanov 
15f14fb602SLionel Sambuc #include "installboot.h"
16f14fb602SLionel Sambuc 
17fa6c4a25SEvgeniy Ivanov #ifndef DFL_SECSIZE
18fa6c4a25SEvgeniy Ivanov #define DFL_SECSIZE     512
19fa6c4a25SEvgeniy Ivanov #endif
20fa6c4a25SEvgeniy Ivanov 
21fa6c4a25SEvgeniy Ivanov #define MFS_FIRST_SUBP_OFFSET	32
22fa6c4a25SEvgeniy Ivanov 
2316440d9bSDavid van Moolenbroek enum {
2416440d9bSDavid van Moolenbroek 	TYPE_BAD,
2516440d9bSDavid van Moolenbroek 	TYPE_PART,
2616440d9bSDavid van Moolenbroek 	TYPE_DISK
2716440d9bSDavid van Moolenbroek };
2816440d9bSDavid van Moolenbroek 
2916440d9bSDavid van Moolenbroek static int
minixfs3_read_mbr(const char * device,char * buf)3016440d9bSDavid van Moolenbroek minixfs3_read_mbr(const char* device, char* buf)
31fa6c4a25SEvgeniy Ivanov {
32fa6c4a25SEvgeniy Ivanov 	int fd;
33fa6c4a25SEvgeniy Ivanov 	int bytes;
34fa6c4a25SEvgeniy Ivanov 	int n;
35fa6c4a25SEvgeniy Ivanov 
36fa6c4a25SEvgeniy Ivanov 	fd = open(device, O_RDONLY);
37fa6c4a25SEvgeniy Ivanov 	if (fd == -1) {
38fa6c4a25SEvgeniy Ivanov 		fprintf(stderr, "Can't open %s: %s\n", device, strerror(errno));
39fa6c4a25SEvgeniy Ivanov 		return 1;
40fa6c4a25SEvgeniy Ivanov 	}
41fa6c4a25SEvgeniy Ivanov 
42fa6c4a25SEvgeniy Ivanov 	if (lseek(fd, MBR_PART_OFFSET, SEEK_SET) != MBR_PART_OFFSET) {
43fa6c4a25SEvgeniy Ivanov 		fprintf(stderr, "Can't seek in %s to %d: %s\n",
44fa6c4a25SEvgeniy Ivanov 			device, MBR_PART_OFFSET, strerror(errno));
45fa6c4a25SEvgeniy Ivanov 		close(fd);
46fa6c4a25SEvgeniy Ivanov 		return 1;
47fa6c4a25SEvgeniy Ivanov 	}
48fa6c4a25SEvgeniy Ivanov 
49fa6c4a25SEvgeniy Ivanov 	bytes = DFL_SECSIZE - MBR_PART_OFFSET;
50fa6c4a25SEvgeniy Ivanov 
51fa6c4a25SEvgeniy Ivanov 	if ((n = read(fd, buf, bytes)) != bytes) {
52fa6c4a25SEvgeniy Ivanov 		fprintf(stderr, "Can't read %d bytes from %s, %d read instead"
53fa6c4a25SEvgeniy Ivanov 			": %s\n",
54fa6c4a25SEvgeniy Ivanov 			bytes, device, n, strerror(errno));
55fa6c4a25SEvgeniy Ivanov 		close(fd);
56fa6c4a25SEvgeniy Ivanov 		return 1;
57fa6c4a25SEvgeniy Ivanov 	}
58fa6c4a25SEvgeniy Ivanov 
59fa6c4a25SEvgeniy Ivanov 	if ((uint8_t)buf[bytes-2] != 0x55 || (uint8_t)buf[bytes-1] != 0xAA) {
60fa6c4a25SEvgeniy Ivanov 		fprintf(stderr, "No MBR on %s, signature is %x\n",
61fa6c4a25SEvgeniy Ivanov 			device, *(uint16_t*)(&buf[bytes-2]));
62fa6c4a25SEvgeniy Ivanov 		close(fd);
63fa6c4a25SEvgeniy Ivanov 		return 1;
64fa6c4a25SEvgeniy Ivanov 	}
65fa6c4a25SEvgeniy Ivanov 
66fa6c4a25SEvgeniy Ivanov 	close(fd);
67fa6c4a25SEvgeniy Ivanov 	return 0;
68fa6c4a25SEvgeniy Ivanov }
69fa6c4a25SEvgeniy Ivanov 
7016440d9bSDavid van Moolenbroek static int
minixfs3_get_dev_type(const char * device,ib_params * params)7116440d9bSDavid van Moolenbroek minixfs3_get_dev_type(const char *device, ib_params *params)
7216440d9bSDavid van Moolenbroek {
7316440d9bSDavid van Moolenbroek 	int len, type;
74fa6c4a25SEvgeniy Ivanov 
7516440d9bSDavid van Moolenbroek 	/*
7616440d9bSDavid van Moolenbroek 	 * Unless the -f flag is given, we expect to be provided with a primary
7716440d9bSDavid van Moolenbroek 	 * partition.  That is, a device name that ends with "pN", N being 0-3.
7816440d9bSDavid van Moolenbroek 	 * If the -f flag is given, we assume that anything else is a whole
7916440d9bSDavid van Moolenbroek 	 * disk.  If we were given a subpartition, it will fail the subsequent
8016440d9bSDavid van Moolenbroek 	 * MBR signature test, so we need not check this explicitly.
8116440d9bSDavid van Moolenbroek 	 */
8216440d9bSDavid van Moolenbroek 	len = strlen(device);
8316440d9bSDavid van Moolenbroek 
8416440d9bSDavid van Moolenbroek 	if (len > 2 && device[len-2] == 'p' &&
8516440d9bSDavid van Moolenbroek 	    (unsigned) (device[len-1] - '0') <= 3) {
8616440d9bSDavid van Moolenbroek 		type = TYPE_PART;
8716440d9bSDavid van Moolenbroek 	} else {
8816440d9bSDavid van Moolenbroek 		type = TYPE_DISK;
8916440d9bSDavid van Moolenbroek 	}
9016440d9bSDavid van Moolenbroek 
9116440d9bSDavid van Moolenbroek 	if (type != TYPE_PART && !(params->flags & IB_FORCE)) {
9216440d9bSDavid van Moolenbroek 		fprintf(stderr, "Wrong device %s, must be /.../cxdyp[0-3]\n",
9316440d9bSDavid van Moolenbroek 			device);
9416440d9bSDavid van Moolenbroek 		return TYPE_BAD;
9516440d9bSDavid van Moolenbroek 	}
9616440d9bSDavid van Moolenbroek 
9716440d9bSDavid van Moolenbroek 	return type;
9816440d9bSDavid van Moolenbroek }
9916440d9bSDavid van Moolenbroek 
10016440d9bSDavid van Moolenbroek int
minixfs3_is_minix_partition(ib_params * params)10116440d9bSDavid van Moolenbroek minixfs3_is_minix_partition(ib_params *params)
102fa6c4a25SEvgeniy Ivanov {
103fa6c4a25SEvgeniy Ivanov 	char buf[DFL_SECSIZE]; /* part table + signature */
104fa6c4a25SEvgeniy Ivanov 
10516440d9bSDavid van Moolenbroek 	if (minixfs3_get_dev_type(params->filesystem, params) == TYPE_BAD)
106fa6c4a25SEvgeniy Ivanov 		return 0;
107fa6c4a25SEvgeniy Ivanov 
108fa6c4a25SEvgeniy Ivanov 	/* MINIX 3 partition with current scheme *must* have subpartitions,
109fa6c4a25SEvgeniy Ivanov 	 * thus MBR has signature. minixfs3_read_mbr checks the signature.
110fa6c4a25SEvgeniy Ivanov 	 */
11116440d9bSDavid van Moolenbroek 	if (minixfs3_read_mbr(params->filesystem, buf))
112fa6c4a25SEvgeniy Ivanov 		return 0;
113fa6c4a25SEvgeniy Ivanov 	return 1;
114fa6c4a25SEvgeniy Ivanov }
115fa6c4a25SEvgeniy Ivanov 
116fa6c4a25SEvgeniy Ivanov /* bootxx from NetBSD is ~8Kb, and old MINIX installations have just
117fa6c4a25SEvgeniy Ivanov  * 1Kb of space for their bootblock. Check if there is enough space
118fa6c4a25SEvgeniy Ivanov  * to install bootxx_minixfs3. New installation should have 16Kb before
119fa6c4a25SEvgeniy Ivanov  * the first subpartition.
120fa6c4a25SEvgeniy Ivanov  */
12116440d9bSDavid van Moolenbroek int
minixfs3_has_bootblock_space(ib_params * params)12216440d9bSDavid van Moolenbroek minixfs3_has_bootblock_space(ib_params *params)
123fa6c4a25SEvgeniy Ivanov {
12416440d9bSDavid van Moolenbroek 	const char *device;
125fa6c4a25SEvgeniy Ivanov 	char buf[DFL_SECSIZE]; /* part table + signature */
12616440d9bSDavid van Moolenbroek 	char parent_name[NAME_MAX];
127fa6c4a25SEvgeniy Ivanov 	struct mbr_partition *part;
128fa6c4a25SEvgeniy Ivanov 	uint32_t first_subpartition = (uint32_t) ~0;
12916440d9bSDavid van Moolenbroek 	uint32_t parent_partition;
13016440d9bSDavid van Moolenbroek 	int i, len, type = 0;
131fa6c4a25SEvgeniy Ivanov 
13216440d9bSDavid van Moolenbroek 	device = params->filesystem;
133fa6c4a25SEvgeniy Ivanov 
13416440d9bSDavid van Moolenbroek 	if ((type = minixfs3_get_dev_type(device, params)) == TYPE_BAD)
13516440d9bSDavid van Moolenbroek 		exit(1);
13616440d9bSDavid van Moolenbroek 
13716440d9bSDavid van Moolenbroek 	if (minixfs3_read_mbr(device, buf))
138fa6c4a25SEvgeniy Ivanov 		exit(1);
139fa6c4a25SEvgeniy Ivanov 
140fa6c4a25SEvgeniy Ivanov 	part = (struct mbr_partition *) buf;
141fa6c4a25SEvgeniy Ivanov 
142fa6c4a25SEvgeniy Ivanov 	for (i = 0; i < 4; i++) {
14316440d9bSDavid van Moolenbroek 		if (part[i].mbrp_size &&
14416440d9bSDavid van Moolenbroek 		    part[i].mbrp_start < first_subpartition)
145fa6c4a25SEvgeniy Ivanov 			first_subpartition = part[i].mbrp_start;
146fa6c4a25SEvgeniy Ivanov 	}
147fa6c4a25SEvgeniy Ivanov 
14816440d9bSDavid van Moolenbroek 	if (type == TYPE_PART) {
14916440d9bSDavid van Moolenbroek 		/* The target is a partition.  Look up its starting offset. */
15016440d9bSDavid van Moolenbroek 		len = strlen(device);
15116440d9bSDavid van Moolenbroek 		strncpy(parent_name, device, len - 2);
15216440d9bSDavid van Moolenbroek 		parent_name[len - 2] = '\0';
153fa6c4a25SEvgeniy Ivanov 
15416440d9bSDavid van Moolenbroek 		if (minixfs3_read_mbr(parent_name, buf))
155fa6c4a25SEvgeniy Ivanov 			exit(1);
156fa6c4a25SEvgeniy Ivanov 
15716440d9bSDavid van Moolenbroek 		parent_partition = 0;
158fa6c4a25SEvgeniy Ivanov 		for (i = 0; i < 4; i++) {
159fa6c4a25SEvgeniy Ivanov 			struct mbr_partition *p = &part[i];
160fa6c4a25SEvgeniy Ivanov 			if (p->mbrp_size && p->mbrp_start <= first_subpartition
16116440d9bSDavid van Moolenbroek 			    && (p->mbrp_start + p->mbrp_size) >
16216440d9bSDavid van Moolenbroek 			    first_subpartition) {
163fa6c4a25SEvgeniy Ivanov 				parent_partition = p->mbrp_start;
164fa6c4a25SEvgeniy Ivanov 				break;
165fa6c4a25SEvgeniy Ivanov 			}
166fa6c4a25SEvgeniy Ivanov 		}
16716440d9bSDavid van Moolenbroek 	} else {
16816440d9bSDavid van Moolenbroek 		/* The target is a whole disk.  The starting offset is 0. */
16916440d9bSDavid van Moolenbroek 		parent_partition = 0;
17016440d9bSDavid van Moolenbroek 	}
171fa6c4a25SEvgeniy Ivanov 
172fa6c4a25SEvgeniy Ivanov 	if ((first_subpartition - parent_partition) < MFS_FIRST_SUBP_OFFSET)
173fa6c4a25SEvgeniy Ivanov 		return 0;
174fa6c4a25SEvgeniy Ivanov 	else
175fa6c4a25SEvgeniy Ivanov 		return 1;
176fa6c4a25SEvgeniy Ivanov }
177