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