xref: /haiku/src/bin/makebootable/platform/bios_ia32/makebootable.cpp (revision 73ad2473e7874b3702cf5b0fdf4c81b747812ed9)
1 /*
2  * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/stat.h>
14 
15 #include <ByteOrder.h>
16 #include <Drivers.h>
17 #include <Entry.h>
18 #include <File.h>
19 #include <fs_info.h>
20 #include <Resources.h>
21 #include <TypeConstants.h>
22 
23 // Linux and FreeBSD support
24 #ifdef HAIKU_HOST_PLATFORM_LINUX
25 #	include <ctype.h>
26 #	include <linux/fs.h>
27 #	include <linux/hdreg.h>
28 #	include <sys/ioctl.h>
29 
30 #	define USE_PARTITION_MAP 1
31 #elif HAIKU_HOST_PLATFORM_FREEBSD
32 #	include <ctype.h>
33 #	include <sys/disklabel.h>
34 #	include <sys/disk.h>
35 #	include <sys/ioctl.h>
36 
37 #	define USE_PARTITION_MAP 1
38 #elif HAIKU_HOST_PLATFORM_DARWIN
39 #	include <ctype.h>
40 #	include <sys/disk.h>
41 #	include <sys/ioctl.h>
42 
43 #	define USE_PARTITION_MAP 1
44 #endif
45 
46 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
47 #	include <image.h>
48 
49 #	include <DiskDevice.h>
50 #	include <DiskDeviceRoster.h>
51 #	include <Partition.h>
52 #	include <Path.h>
53 
54 #	include "bfs_control.h"
55 #endif
56 
57 #if USE_PARTITION_MAP
58 #	include "PartitionMap.h"
59 #	include "PartitionMapParser.h"
60 #endif
61 
62 
63 static const char *kCommandName = "makebootable";
64 
65 static const int kBootCodeSize				= 1024;
66 static const int kFirstBootCodePartSize		= 512;
67 static const int kSecondBootCodePartOffset	= 676;
68 static const int kSecondBootCodePartSize	= kBootCodeSize
69 												- kSecondBootCodePartOffset;
70 static const int kPartitionOffsetOffset		= 506;
71 
72 static int kArgc;
73 static const char *const *kArgv;
74 
75 // usage
76 const char *kUsage =
77 "Usage: %s [ options ] <file> ...\n"
78 "\n"
79 "Makes the specified BFS partitions/devices bootable by writing boot code\n"
80 "into the first two sectors. It doesn't mark the partition(s) active.\n"
81 "\n"
82 "If a given <file> refers to a directory, the partition/device on which the\n"
83 "directory resides will be made bootable. If it refers to a regular file,\n"
84 "the file is considered a disk image and the boot code will be written to\n"
85 "it.\n"
86 "\n"
87 "Options:\n"
88 "  -h, --help    - Print this help text and exit.\n"
89 "  --dry-run     - Do everything but actually writing the boot block to disk.\n"
90 "\n"
91 "[compatibility]\n"
92 "  -alert        - Compatibility option. Ignored.\n"
93 "  -full         - Compatibility option. Ignored.\n"
94 "  -safe         - Compatibility option. Fail when specified.\n"
95 ;
96 
97 
98 // print_usage
99 static void
100 print_usage(bool error)
101 {
102 	// get command name
103 	const char *commandName = NULL;
104 	if (kArgc > 0) {
105 		if (const char *lastSlash = strchr(kArgv[0], '/'))
106 			commandName = lastSlash + 1;
107 		else
108 			commandName = kArgv[0];
109 	}
110 
111 	if (!commandName || strlen(commandName) == 0)
112 		commandName = kCommandName;
113 
114 	// print usage
115 	fprintf((error ? stderr : stdout), kUsage, commandName, commandName,
116 		commandName);
117 }
118 
119 
120 // print_usage_and_exit
121 static void
122 print_usage_and_exit(bool error)
123 {
124 	print_usage(error);
125 	exit(error ? 1 : 0);
126 }
127 
128 
129 // read_boot_code_data
130 static uint8 *
131 read_boot_code_data(const char* programPath)
132 {
133 	// open our executable
134 	BFile executableFile;
135 	status_t error = executableFile.SetTo(programPath, B_READ_ONLY);
136 	if (error != B_OK) {
137 		fprintf(stderr, "Error: Failed to open my executable file (\"%s\": "
138 			"%s\n", programPath, strerror(error));
139 		exit(1);
140 	}
141 
142 	uint8 *bootCodeData = new uint8[kBootCodeSize];
143 
144 	// open our resources
145 	BResources resources;
146 	error = resources.SetTo(&executableFile);
147 	const void *resourceData = NULL;
148 	if (error == B_OK) {
149 		// read the boot block from the resources
150 		size_t resourceSize;
151 		resourceData = resources.LoadResource(B_RAW_TYPE, 666, &resourceSize);
152 
153 		if (resourceData && resourceSize != (size_t)kBootCodeSize) {
154 			resourceData = NULL;
155 			printf("Warning: Something is fishy with my resources! The boot "
156 				"code doesn't have the correct size. Trying the attribute "
157 				"instead ...\n");
158 		}
159 	}
160 
161 	if (resourceData) {
162 		// found boot data in the resources
163 		memcpy(bootCodeData, resourceData, kBootCodeSize);
164 	} else {
165 		// no boot data in the resources; try the attribute
166 		ssize_t bytesRead = executableFile.ReadAttr("BootCode", B_RAW_TYPE,
167 			0, bootCodeData, kBootCodeSize);
168 		if (bytesRead < 0) {
169 			fprintf(stderr, "Error: Failed to read boot code from resources "
170 				"or attribute.\n");
171 			exit(1);
172 		}
173 		if (bytesRead != kBootCodeSize) {
174 			fprintf(stderr, "Error: Failed to read boot code from resources, "
175 				"and the boot code in the attribute has the wrong size!\n");
176 			exit(1);
177 		}
178 	}
179 
180 	return bootCodeData;
181 }
182 
183 
184 // write_boot_code_part
185 static void
186 write_boot_code_part(const char *fileName, int fd, off_t imageOffset,
187 	const uint8 *bootCodeData, int offset, int size, bool dryRun)
188 {
189 	if (!dryRun) {
190 		ssize_t bytesWritten = write_pos(fd, imageOffset + offset,
191 			bootCodeData + offset, size);
192 		if (bytesWritten != size) {
193 			fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName,
194 				strerror(bytesWritten < 0 ? errno : B_ERROR));
195 		}
196 	}
197 }
198 
199 
200 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
201 
202 static status_t
203 find_own_image(image_info *info)
204 {
205 	int32 cookie = 0;
206 	while (get_next_image_info(B_CURRENT_TEAM, &cookie, info) == B_OK) {
207 		if (((addr_t)info->text <= (addr_t)find_own_image
208 			&& (addr_t)info->text + info->text_size
209 				> (addr_t)find_own_image)) {
210 			return B_OK;
211 		}
212 	}
213 
214 	return B_NAME_NOT_FOUND;
215 }
216 
217 #endif
218 
219 
220 #if USE_PARTITION_MAP
221 
222 static void
223 dump_partition_map(const PartitionMap& map)
224 {
225 	fprintf(stderr, "partitions:\n");
226 	int32 count = map.CountPartitions();
227 	for (int i = 0; i < count; i++) {
228 		const Partition* partition = map.PartitionAt(i);
229 		fprintf(stderr, "%2d: ", i);
230 		if (partition == NULL) {
231 			fprintf(stderr, "<null>\n");
232 			continue;
233 		}
234 
235 		if (partition->IsEmpty()) {
236 			fprintf(stderr, "<empty>\n");
237 			continue;
238 		}
239 
240 		fprintf(stderr, "offset: %16" B_PRIdOFF ", size: %16" B_PRIdOFF
241 			", type: %x%s\n", partition->Offset(), partition->Size(),
242 			partition->Type(), partition->IsExtended() ? " (extended)" : "");
243 	}
244 }
245 
246 #endif
247 
248 
249 // main
250 int
251 main(int argc, const char *const *argv)
252 {
253 	kArgc = argc;
254 	kArgv = argv;
255 
256 	if (argc < 2)
257 		print_usage_and_exit(true);
258 
259 	// parameters
260 	const char **files = new const char*[argc];
261 	int fileCount = 0;
262 	bool dryRun = false;
263 	off_t startOffset = 0;
264 
265 	// parse arguments
266 	for (int argi = 1; argi < argc;) {
267 		const char *arg = argv[argi++];
268 
269 		if (arg[0] == '-') {
270 			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
271 				print_usage_and_exit(false);
272 			} else if (strcmp(arg, "--dry-run") == 0) {
273 				dryRun = true;
274 			} else if (strcmp(arg, "-alert") == 0) {
275 				// ignore
276 			} else if (strcmp(arg, "-full") == 0) {
277 				// ignore
278 			} else if (strcmp(arg, "--start-offset") == 0) {
279 				if (argi >= argc)
280 					print_usage_and_exit(true);
281 				startOffset = strtoll(argv[argi++], NULL, 0);
282 			} else if (strcmp(arg, "-safe") == 0) {
283 				fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n");
284 				exit(1);
285 			} else {
286 				print_usage_and_exit(true);
287 			}
288 
289 		} else {
290 			files[fileCount++] = arg;
291 		}
292 	}
293 
294 	// we need at least one file
295 	if (fileCount == 0)
296 		print_usage_and_exit(true);
297 
298 	// read the boot code
299 	uint8 *bootCodeData = NULL;
300 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
301 	bootCodeData = read_boot_code_data(argv[0]);
302 #else
303 	image_info info;
304 	if (find_own_image(&info) == B_OK)
305 		bootCodeData = read_boot_code_data(info.name);
306 #endif
307 	if (!bootCodeData) {
308 		fprintf(stderr, "Error: Failed to read \n");
309 		exit(1);
310 	}
311 
312 	// iterate through the files and make them bootable
313 	status_t error;
314 	for (int i = 0; i < fileCount; i++) {
315 		const char *fileName = files[i];
316 		BEntry entry;
317 		error = entry.SetTo(fileName, true);
318 		if (error != B_OK) {
319 			fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
320 				fileName, strerror(error));
321 			exit(1);
322 		}
323 
324 		// get stat to check the type of the file
325 		struct stat st;
326 		error = entry.GetStat(&st);
327 		if (error != B_OK) {
328 			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n",
329 				fileName, strerror(error));
330 			exit(1);
331 		}
332 
333 		bool noPartition = false;
334 		int64 partitionOffset = 0;
335 		fs_info info;	// needs to be here (we use the device name later)
336 		if (S_ISDIR(st.st_mode)) {
337 			#ifdef HAIKU_TARGET_PLATFORM_HAIKU
338 
339 				// a directory: get the device
340 				error = fs_stat_dev(st.st_dev, &info);
341 				if (error != B_OK) {
342 					fprintf(stderr, "Error: Failed to determine device for "
343 						"\"%s\": %s\n", fileName, strerror(error));
344 					exit(1);
345 				}
346 
347 				fileName = info.device_name;
348 
349 			#else
350 
351 				(void)info;
352 				fprintf(stderr, "Error: Specifying directories not supported "
353 					"on this platform!\n");
354 				exit(1);
355 
356 			#endif
357 
358 		} else if (S_ISREG(st.st_mode)) {
359 			// a regular file: fine
360 			noPartition = true;
361 		} else if (S_ISCHR(st.st_mode)) {
362 			// character special: a device or partition under BeOS
363 			// or under FreeBSD
364 			#if !defined(HAIKU_TARGET_PLATFORM_HAIKU) \
365 				&& !defined(HAIKU_HOST_PLATFORM_FREEBSD)
366 
367 				fprintf(stderr, "Error: Character special devices not "
368 					"supported on this platform.\n");
369 				exit(1);
370 
371 			#endif
372 
373 			#ifdef HAIKU_HOST_PLATFORM_FREEBSD
374 
375 				// chop off the trailing number
376 				int fileNameLen = strlen(fileName);
377 				int baseNameLen = -1;
378 				for (int k = fileNameLen - 1; k >= 0; k--) {
379 					if (!isdigit(fileName[k])) {
380 						baseNameLen = k + 1;
381 						break;
382 					}
383 				}
384 
385 				// Remove de 's' from 'ad2s2' slice device (partition for DOS
386 				// users) to get 'ad2' base device
387 				baseNameLen--;
388 
389 				if (baseNameLen < 0) {
390 					// only digits?
391 					fprintf(stderr, "Error: Failed to get base device name.\n");
392 					exit(1);
393 				}
394 
395 				if (baseNameLen < fileNameLen) {
396 					// get base device name and partition index
397 					char baseDeviceName[B_PATH_NAME_LENGTH];
398 					int partitionIndex = atoi(fileName + baseNameLen + 1);
399 						// Don't forget the 's' of slice :)
400 					memcpy(baseDeviceName, fileName, baseNameLen);
401 					baseDeviceName[baseNameLen] = '\0';
402 
403 					// open base device
404 					int baseFD = open(baseDeviceName, O_RDONLY);
405 					if (baseFD < 0) {
406 						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
407 							baseDeviceName, strerror(errno));
408 						exit(1);
409 					}
410 
411 					// get device size
412 					int64 deviceSize;
413 					if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) {
414 						fprintf(stderr, "Error: Failed to get device geometry "
415 							"for \"%s\": %s\n", baseDeviceName,
416 							strerror(errno));
417 						exit(1);
418 					}
419 
420 					// parse the partition map
421 					// TODO: block size!
422 					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
423 					PartitionMap map;
424 					error = parser.Parse(NULL, &map);
425 					if (error != B_OK) {
426 						fprintf(stderr, "Error: Parsing partition table on "
427 							"device \"%s\" failed: %s\n", baseDeviceName,
428 							strerror(error));
429 						exit(1);
430 					}
431 
432 					close(baseFD);
433 
434 					// check the partition we are supposed to write at
435 					Partition *partition = map.PartitionAt(partitionIndex - 1);
436 					if (!partition || partition->IsEmpty()) {
437 						fprintf(stderr, "Error: Invalid partition index %d.\n",
438 							partitionIndex);
439 						dump_partition_map(map);
440 						exit(1);
441 					}
442 
443 					if (partition->IsExtended()) {
444 						fprintf(stderr, "Error: Partition %d is an extended "
445 							"partition.\n", partitionIndex);
446 						dump_partition_map(map);
447 						exit(1);
448 					}
449 
450 					partitionOffset = partition->Offset();
451 
452 				} else {
453 					// The given device is the base device. We'll write at
454 					// offset 0.
455 				}
456 
457 			#endif // HAIKU_HOST_PLATFORM_FREEBSD
458 
459 		} else if (S_ISBLK(st.st_mode)) {
460 			// block device: a device or partition under Linux or Darwin
461 			#ifdef HAIKU_HOST_PLATFORM_LINUX
462 
463 				// chop off the trailing number
464 				int fileNameLen = strlen(fileName);
465 				int baseNameLen = -1;
466 				for (int k = fileNameLen - 1; k >= 0; k--) {
467 					if (!isdigit(fileName[k])) {
468 						baseNameLen = k + 1;
469 						break;
470 					}
471 				}
472 
473 				if (baseNameLen < 0) {
474 					// only digits?
475 					fprintf(stderr, "Error: Failed to get base device name.\n");
476 					exit(1);
477 				}
478 
479 				if (baseNameLen < fileNameLen) {
480 					// get base device name and partition index
481 					char baseDeviceName[B_PATH_NAME_LENGTH];
482 					int partitionIndex = atoi(fileName + baseNameLen);
483 					memcpy(baseDeviceName, fileName, baseNameLen);
484 					baseDeviceName[baseNameLen] = '\0';
485 
486 					// open base device
487 					int baseFD = open(baseDeviceName, O_RDONLY);
488 					if (baseFD < 0) {
489 						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
490 							baseDeviceName, strerror(errno));
491 						exit(1);
492 					}
493 
494 					// get device size -- try BLKGETSIZE64, but, if it doesn't
495 					// work, fall back to the obsolete HDIO_GETGEO
496 					int64 deviceSize;
497 					hd_geometry geometry;
498 					if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0
499 						&& deviceSize > 0) {
500 						// looks good
501 					} else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) {
502 						deviceSize = (int64)geometry.heads * geometry.sectors
503 							* geometry.cylinders * 512;
504 					} else {
505 						fprintf(stderr, "Error: Failed to get device geometry "
506 							"for \"%s\": %s\n", baseDeviceName,
507 							strerror(errno));
508 						exit(1);
509 					}
510 
511 					// parse the partition map
512 					// TODO: block size!
513 					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
514 					PartitionMap map;
515 					error = parser.Parse(NULL, &map);
516 					if (error != B_OK) {
517 						fprintf(stderr, "Error: Parsing partition table on "
518 							"device \"%s\" failed: %s\n", baseDeviceName,
519 							strerror(error));
520 						exit(1);
521 					}
522 
523 					close(baseFD);
524 
525 					// check the partition we are supposed to write at
526 					Partition *partition = map.PartitionAt(partitionIndex - 1);
527 					if (!partition || partition->IsEmpty()) {
528 						fprintf(stderr, "Error: Invalid partition index %d.\n",
529 							partitionIndex);
530 						dump_partition_map(map);
531 						exit(1);
532 					}
533 
534 					if (partition->IsExtended()) {
535 						fprintf(stderr, "Error: Partition %d is an extended "
536 							"partition.\n", partitionIndex);
537 						dump_partition_map(map);
538 						exit(1);
539 					}
540 
541 					partitionOffset = partition->Offset();
542 				} else {
543 					// The given device is the base device. We'll write at
544 					// offset 0.
545 				}
546 
547 			#elif defined(HAIKU_HOST_PLATFORM_DARWIN)
548 				// chop off the trailing number
549 				int fileNameLen = strlen(fileName);
550 				int baseNameLen = fileNameLen - 2;
551 
552 				// get base device name and partition index
553 				char baseDeviceName[B_PATH_NAME_LENGTH];
554 				int partitionIndex = atoi(fileName + baseNameLen + 1);
555 				memcpy(baseDeviceName, fileName, baseNameLen);
556 				baseDeviceName[baseNameLen] = '\0';
557 
558 				// open base device
559 				int baseFD = open(baseDeviceName, O_RDONLY);
560 				if (baseFD < 0) {
561 					fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
562 							baseDeviceName, strerror(errno));
563 					exit(1);
564 				}
565 
566 				// get device size
567 				int64 blockSize;
568 				int64 blockCount;
569 				int64 deviceSize;
570 				if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) {
571 					fprintf(stderr, "Error: Failed to get block size "
572 							"for \"%s\": %s\n", baseDeviceName,
573 							strerror(errno));
574 					exit(1);
575 				}
576 				if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) {
577 					fprintf(stderr, "Error: Failed to get block count "
578 							"for \"%s\": %s\n", baseDeviceName,
579 							strerror(errno));
580 					exit(1);
581 				}
582 
583 				deviceSize = blockSize * blockCount;
584 
585 				// parse the partition map
586 				PartitionMapParser parser(baseFD, 0, deviceSize, blockSize);
587 				PartitionMap map;
588 				error = parser.Parse(NULL, &map);
589 				if (error != B_OK) {
590 					fprintf(stderr, "Error: Parsing partition table on "
591 							"device \"%s\" failed: %s\n", baseDeviceName,
592 							strerror(error));
593 					exit(1);
594 				}
595 
596 				close(baseFD);
597 
598 				// check the partition we are supposed to write at
599 				Partition *partition = map.PartitionAt(partitionIndex - 1);
600 				if (!partition || partition->IsEmpty()) {
601 					fprintf(stderr, "Error: Invalid partition index %d.\n",
602 						partitionIndex);
603 					dump_partition_map(map);
604 					exit(1);
605 				}
606 
607 				if (partition->IsExtended()) {
608 					fprintf(stderr, "Error: Partition %d is an extended "
609 						"partition.\n", partitionIndex);
610 					dump_partition_map(map);
611 					exit(1);
612 				}
613 				partitionOffset = partition->Offset();
614 			#else
615 			// partitions are block devices under Haiku, but not under BeOS
616 			#ifdef HAIKU_TARGET_PLATFORM_HAIKU
617 				fprintf(stderr, "Error: Block devices not supported on this "
618 					"platform!\n");
619 				exit(1);
620 			#endif	// HAIKU_TARGET_PLATFORM_HAIKU
621 
622 			#endif
623 		} else {
624 			fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
625 				fileName);
626 			exit(1);
627 		}
628 
629 		// open the file
630 		int fd = open(fileName, O_RDWR);
631 		if (fd < 0) {
632 			fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName,
633 				strerror(errno));
634 			exit(1);
635 		}
636 
637 		#ifdef HAIKU_TARGET_PLATFORM_HAIKU
638 
639 			// get a partition info
640 			if (!noPartition
641 				&& strlen(fileName) >= 3
642 				&& strncmp("raw", fileName + strlen(fileName) - 3, 3)) {
643 				partition_info partitionInfo;
644 				if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
645 						sizeof(partitionInfo)) == 0) {
646 					partitionOffset = partitionInfo.offset;
647 				} else {
648 					fprintf(stderr, "Error: Failed to get partition info: %s\n",
649 						strerror(errno));
650 					exit(1);
651 				}
652 			}
653 
654 		#endif	// __BEOS__
655 
656 		// adjust the partition offset in the boot code data
657 		// hard coded sector size: 512 bytes
658 		*(uint32*)(bootCodeData + kPartitionOffsetOffset)
659 			= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));
660 
661 		// write the boot code
662 		printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64
663 			" bytes, start offset = %" B_PRIdOFF ") "
664 			"...\n", fileName, partitionOffset, startOffset);
665 
666 		write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0,
667 			kFirstBootCodePartSize, dryRun);
668 		write_boot_code_part(fileName, fd, startOffset, bootCodeData,
669 			kSecondBootCodePartOffset, kSecondBootCodePartSize,
670 			dryRun);
671 
672 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
673 		// check if this partition is mounted
674 		BDiskDeviceRoster roster;
675 		BPartition* partition;
676 		BDiskDevice device;
677 		status_t status = roster.GetPartitionForPath(fileName, &device,
678 			&partition);
679 		if (status != B_OK) {
680 			status = roster.GetFileDeviceForPath(fileName, &device);
681 			if (status == B_OK)
682 				partition = &device;
683 		}
684 		if (status == B_OK && partition->IsMounted() && !dryRun) {
685 			// This partition is mounted, we need to tell BFS to update its
686 			// boot block (we are using part of the same logical block).
687 			BPath path;
688 			status = partition->GetMountPoint(&path);
689 			if (status == B_OK) {
690 				update_boot_block update;
691 				update.offset = kSecondBootCodePartOffset - 512;
692 				update.data = bootCodeData + kSecondBootCodePartOffset;
693 				update.length = kSecondBootCodePartSize;
694 
695 				int mountFD = open(path.Path(), O_RDONLY);
696 				if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update,
697 						sizeof(update_boot_block)) != 0) {
698 					fprintf(stderr, "Could not update BFS boot block: %s\n",
699 						strerror(errno));
700 				}
701 				close(mountFD);
702 			} else {
703 				fprintf(stderr, "Could not update BFS boot code while the "
704 					"partition is mounted!\n");
705 			}
706 		}
707 #endif	// HAIKU_TARGET_PLATFORM_HAIKU
708 
709 		close(fd);
710 	}
711 
712 	return 0;
713 }
714