Example #1
0
void
MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition)
{
	if (!disk || selectedPartition < 0) {
		_DisplayPartitionError(B_TRANSLATE("You need to select a partition "
			"entry from the list."));
		return;
	}

	BPartition* partition = disk->FindDescendant(selectedPartition);
	if (!partition) {
		_DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
			"partition by ID."));
		return;
	}

	if (!partition->IsMounted()) {
		status_t ret = partition->Mount();
		if (ret < B_OK) {
			_DisplayPartitionError(
				B_TRANSLATE("Could not mount partition %s."), partition, ret);
		} else {
			// successful mount, adapt to the changes
			_ScanDrives();
		}
	} else {
		_DisplayPartitionError(
			B_TRANSLATE("The partition %s is already mounted."), partition);
	}
}
Example #2
0
void
MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition)
{
	if (!disk || selectedPartition < 0) {
		_DisplayPartitionError(B_TRANSLATE("You need to select a partition "
			"entry from the list."));
		return;
	}

	BPartition* partition = disk->FindDescendant(selectedPartition);
	if (!partition) {
		_DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
			"partition by ID."));
		return;
	}

	if (partition->IsMounted()) {
		BPath path;
		partition->GetMountPoint(&path);
		status_t ret = partition->Unmount();
		if (ret < B_OK) {
			_DisplayPartitionError(
				B_TRANSLATE("Could not unmount partition %s."),
				partition, ret);
		} else {
			if (dev_for_path(path.Path()) == dev_for_path("/"))
				rmdir(path.Path());
			// successful unmount, adapt to the changes
			_ScanDrives();
		}
	} else {
		_DisplayPartitionError(
			B_TRANSLATE("The partition %s is already unmounted."),
			partition);
	}
}
Example #3
0
void
WorkerThread::MessageReceived(BMessage* message)
{
	CALLED();

	switch (message->what) {
		case MSG_START_INSTALLING:
			_PerformInstall(fWindow->GetSourceMenu(), fWindow->GetTargetMenu());
			break;

		case MSG_WRITE_BOOT_SECTOR:
		{
			int32 id;
			if (message->FindInt32("id", &id) != B_OK) {
				_SetStatusMessage(B_TRANSLATE("Boot sector not written "
					"because of an internal error."));
				break;
			}

			// TODO: Refactor with _PerformInstall()
			BPath targetDirectory;
			BDiskDevice device;
			BPartition* partition;

			if (fDDRoster.GetPartitionWithID(id, &device, &partition) == B_OK) {
				if (!partition->IsMounted()) {
					if (partition->Mount() < B_OK) {
						_SetStatusMessage(B_TRANSLATE("The partition can't be "
							"mounted. Please choose a different partition."));
						break;
					}
				}
				if (partition->GetMountPoint(&targetDirectory) != B_OK) {
					_SetStatusMessage(B_TRANSLATE("The mount point could not "
						"be retrieved."));
					break;
				}
			} else if (fDDRoster.GetDeviceWithID(id, &device) == B_OK) {
				if (!device.IsMounted()) {
					if (device.Mount() < B_OK) {
						_SetStatusMessage(B_TRANSLATE("The disk can't be "
							"mounted. Please choose a different disk."));
						break;
					}
				}
				if (device.GetMountPoint(&targetDirectory) != B_OK) {
					_SetStatusMessage(B_TRANSLATE("The mount point could not "
						"be retrieved."));
					break;
				}
			}

			_LaunchFinishScript(targetDirectory);
			// TODO: Get error from executing script!
			_SetStatusMessage(
				B_TRANSLATE("Boot sector successfully written."));
		}
		default:
			BLooper::MessageReceived(message);
	}
}
Example #4
0
void
WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
{
	CALLED();

	BPath targetDirectory;
	BPath srcDirectory;
	BPath trashPath;
	BPath testPath;
	BDirectory targetDir;
	BDiskDevice device;
	BPartition* partition;
	BVolume targetVolume;
	status_t err = B_OK;
	int32 entries = 0;
	entry_ref testRef;
	const char* mountError = B_TRANSLATE("The disk can't be mounted. Please "
		"choose a different disk.");

	BMessenger messenger(fWindow);
	ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE));
	CopyEngine engine(&reporter);
	BList unzipEngines;

	PartitionMenuItem* targetItem = (PartitionMenuItem*)targetMenu->FindMarked();
	PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked();
	if (!srcItem || !targetItem) {
		ERR("bad menu items\n");
		goto error;
	}

	// check if target is initialized
	// ask if init or mount as is
	if (fDDRoster.GetPartitionWithID(targetItem->ID(), &device,
			&partition) == B_OK) {
		if (!partition->IsMounted()) {
			if ((err = partition->Mount()) < B_OK) {
				_SetStatusMessage(mountError);
				ERR("BPartition::Mount");
				goto error;
			}
		}
		if ((err = partition->GetVolume(&targetVolume)) != B_OK) {
			ERR("BPartition::GetVolume");
			goto error;
		}
		if ((err = partition->GetMountPoint(&targetDirectory)) != B_OK) {
			ERR("BPartition::GetMountPoint");
			goto error;
		}
	} else if (fDDRoster.GetDeviceWithID(targetItem->ID(), &device) == B_OK) {
		if (!device.IsMounted()) {
			if ((err = device.Mount()) < B_OK) {
				_SetStatusMessage(mountError);
				ERR("BDiskDevice::Mount");
				goto error;
			}
		}
		if ((err = device.GetVolume(&targetVolume)) != B_OK) {
			ERR("BDiskDevice::GetVolume");
			goto error;
		}
		if ((err = device.GetMountPoint(&targetDirectory)) != B_OK) {
			ERR("BDiskDevice::GetMountPoint");
			goto error;
		}
	} else
		goto error; // shouldn't happen

	// check if target has enough space
	if ((fSpaceRequired > 0 && targetVolume.FreeBytes() < fSpaceRequired)
		&& ((new BAlert("", B_TRANSLATE("The destination disk may not have "
			"enough space. Try choosing a different disk or choose to not "
			"install optional items."), B_TRANSLATE("Try installing anyway"),
			B_TRANSLATE("Cancel"), 0,
			B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) {
		goto error;
	}

	if (fDDRoster.GetPartitionWithID(srcItem->ID(), &device, &partition) == B_OK) {
		if ((err = partition->GetMountPoint(&srcDirectory)) != B_OK) {
			ERR("BPartition::GetMountPoint");
			goto error;
		}
	} else if (fDDRoster.GetDeviceWithID(srcItem->ID(), &device) == B_OK) {
		if ((err = device.GetMountPoint(&srcDirectory)) != B_OK) {
			ERR("BDiskDevice::GetMountPoint");
			goto error;
		}
	} else
		goto error; // shouldn't happen

	// check not installing on itself
	if (strcmp(srcDirectory.Path(), targetDirectory.Path()) == 0) {
		_SetStatusMessage(B_TRANSLATE("You can't install the contents of a "
			"disk onto itself. Please choose a different disk."));
		goto error;
	}

	// check not installing on boot volume
	if ((strncmp(BOOT_PATH, targetDirectory.Path(), strlen(BOOT_PATH)) == 0)
		&& ((new BAlert("", B_TRANSLATE("Are you sure you want to install "
			"onto the current boot disk? The Installer will have to reboot "
			"your machine if you proceed."), B_TRANSLATE("OK"),
			B_TRANSLATE("Cancel"), 0,
			B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) {
		_SetStatusMessage("Installation stopped.");
		goto error;
	}

	// check if target volume's trash dir has anything in it
	// (target volume w/ only an empty trash dir is considered
	// an empty volume)
	if (find_directory(B_TRASH_DIRECTORY, &trashPath, false,
		&targetVolume) == B_OK && targetDir.SetTo(trashPath.Path()) == B_OK) {
			while (targetDir.GetNextRef(&testRef) == B_OK) {
				// Something in the Trash
				entries++;
				break;
			}
	}

	targetDir.SetTo(targetDirectory.Path());

	// check if target volume otherwise has any entries
	while (entries == 0 && targetDir.GetNextRef(&testRef) == B_OK) {
		if (testPath.SetTo(&testRef) == B_OK && testPath != trashPath)
			entries++;
	}

	if (entries != 0
		&& ((new BAlert("", B_TRANSLATE("The target volume is not empty. Are "
			"you sure you want to install anyway?\n\nNote: The 'system' folder "
			"will be a clean copy from the source volume, all other folders "
			"will be merged, whereas files and links that exist on both the "
			"source and target volume will be overwritten with the source "
			"volume version."),
			B_TRANSLATE("Install anyway"), B_TRANSLATE("Cancel"), 0,
			B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) {
		// TODO: Would be cool to offer the option here to clean additional
		// folders at the user's choice (like /boot/common and /boot/develop).
		err = B_CANCELED;
		goto error;
	}

	// Begin actual installation

	_LaunchInitScript(targetDirectory);

	// Create the default indices which should always be present on a proper
	// boot volume. We don't care if the source volume does not have them.
	// After all, the user might be re-installing to another drive and may
	// want problems fixed along the way...
	err = _CreateDefaultIndices(targetDirectory);
	if (err != B_OK)
		goto error;
	// Mirror all the indices which are present on the source volume onto
	// the target volume.
	err = _MirrorIndices(srcDirectory, targetDirectory);
	if (err != B_OK)
		goto error;

	// Let the engine collect information for the progress bar later on
	engine.ResetTargets(srcDirectory.Path());
	err = engine.CollectTargets(srcDirectory.Path(), fCancelSemaphore);
	if (err != B_OK)
		goto error;

	// Collect selected packages also
	if (fPackages) {
		BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY);
		int32 count = fPackages->CountItems();
		for (int32 i = 0; i < count; i++) {
			Package *p = static_cast<Package*>(fPackages->ItemAt(i));
			BPath packageDir(pkgRootDir.Path(), p->Folder());
			err = engine.CollectTargets(packageDir.Path(), fCancelSemaphore);
			if (err != B_OK)
				goto error;
		}
	}

	// collect information about all zip packages
	err = _ProcessZipPackages(srcDirectory.Path(), targetDirectory.Path(),
		&reporter, unzipEngines);
	if (err != B_OK)
		goto error;

	reporter.StartTimer();

	// copy source volume
	err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(),
		fCancelSemaphore);
	if (err != B_OK)
		goto error;

	// copy selected packages
	if (fPackages) {
		BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY);
		int32 count = fPackages->CountItems();
		for (int32 i = 0; i < count; i++) {
			Package *p = static_cast<Package*>(fPackages->ItemAt(i));
			BPath packageDir(pkgRootDir.Path(), p->Folder());
			err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(),
				fCancelSemaphore);
			if (err != B_OK)
				goto error;
		}
	}

	// Extract all zip packages. If an error occured, delete the rest of
	// the engines, but stop extracting.
	for (int32 i = 0; i < unzipEngines.CountItems(); i++) {
		UnzipEngine* engine = reinterpret_cast<UnzipEngine*>(
			unzipEngines.ItemAtFast(i));
		if (err == B_OK)
			err = engine->UnzipPackage();
		delete engine;
	}
	if (err != B_OK)
		goto error;

	_LaunchFinishScript(targetDirectory);

	BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);

	return;
error:
	BMessage statusMessage(MSG_RESET);
	if (err == B_CANCELED)
		_SetStatusMessage(B_TRANSLATE("Installation canceled."));
	else
		statusMessage.AddInt32("error", err);
	ERR("_PerformInstall failed");
	BMessenger(fWindow).SendMessage(&statusMessage);
}
Example #5
0
int
main(int argc, char** argv)
{
	const struct option kLongOptions[] = {
		{ "help", 0, NULL, 'h' },
		{ "check-only", 0, NULL, 'c' },
		{ NULL, 0, NULL, 0 }
	};
	const char* kShortOptions = "hc";

	// parse argument list
	bool checkOnly = false;

	while (true) {
		int nextOption = getopt_long(argc, argv, kShortOptions, kLongOptions,
			NULL);
		if (nextOption == -1)
			break;

		switch (nextOption) {
			case 'h':	// --help
				usage(stdout);
				return 0;
			case 'c':	// --check-only
				checkOnly = true;
				break;
			default:	// everything else
				usage(stderr);
				return 1;
		}
	}

	// the device name should be the only non-option element
	if (optind != argc - 1) {
		usage(stderr);
		return 1;
	}

	const char* path = argv[optind];
	//UnregisterFileDevice unregisterFileDevice;

	BDiskDeviceRoster roster;
	BPartition* partition;
	BDiskDevice device;

	status_t status = roster.GetPartitionForPath(path, &device,
		&partition);
	if (status != B_OK) {
		if (strncmp(path, "/dev", 4)) {
			// try mounted volume
			status = roster.FindPartitionByMountPoint(path, &device, &partition)
				? B_OK : B_BAD_VALUE;
		}

		// TODO: try to register file device

		if (status != B_OK) {
			fprintf(stderr, "%s: Failed to get disk device for path \"%s\": "
				"%s\n", kProgramName, path, strerror(status));
			return 1;
		}
	}

	// Prepare the device for modifications

	status = device.PrepareModifications();
	if (status != B_OK) {
		fprintf(stderr, "%s: Could not prepare the device for modifications: "
			"%s\n", kProgramName, strerror(status));
		return 1;
	}

	// Check if the partition supports repairing

	bool canRepairWhileMounted;
	bool canRepair = partition->CanRepair(checkOnly, &canRepairWhileMounted);
	if (!canRepair && !canRepairWhileMounted) {
		fprintf(stderr, "%s: The disk system does not support repairing.\n",
			kProgramName);
		return 1;
	}

	if (partition->IsMounted() && !canRepairWhileMounted) {
		fprintf(stderr, "%s: The disk system does not support repairing a "
			"mounted volume.\n", kProgramName);
		return 1;
	}
	if (!partition->IsMounted() && !canRepair) {
		fprintf(stderr, "%s: The disk system does not support repairing a "
			"volume that is not mounted.\n", kProgramName);
		return 1;
	}

	BDiskSystem diskSystem;
	status = partition->GetDiskSystem(&diskSystem);
	if (status != B_OK) {
		fprintf(stderr, "%s: Failed to get disk system for partition: %s\n",
			kProgramName, strerror(status));
		return 1;
	}

	// Repair the volume

	status = partition->Repair(checkOnly);
	if (status != B_OK) {
		fprintf(stderr, "%s: Repairing failed: %s\n", kProgramName,
			strerror(status));
		return 1;
	}

	status = device.CommitModifications();

	return 0;
}
Example #6
0
void
MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition,
	const BString& diskSystemName)
{
	if (!disk || selectedPartition < 0) {
		_DisplayPartitionError(B_TRANSLATE("You need to select a partition "
			"entry from the list."));
		return;
	}

	if (disk->IsReadOnly()) {
		_DisplayPartitionError(B_TRANSLATE("The selected disk is read-only."));
		return;
	}

	BPartition* partition = disk->FindDescendant(selectedPartition);
	if (!partition) {
		_DisplayPartitionError(B_TRANSLATE("Unable to find the selected "
			"partition by ID."));
		return;
	}

	if (partition->IsMounted()) {
		_DisplayPartitionError(
			B_TRANSLATE("The partition %s is currently mounted."));
		// TODO: option to unmount and continue on success to unmount
		return;
	}

	BDiskSystem diskSystem;
	fDDRoster.RewindDiskSystems();
	bool found = false;
	while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) {
		if (diskSystem.SupportsInitializing()) {
			if (diskSystemName == diskSystem.PrettyName()) {
				found = true;
				break;
			}
		}
	}

	char message[512];

	if (!found) {
		snprintf(message, sizeof(message), B_TRANSLATE("Disk system \"%s\"\" "
			"not found!"));
		_DisplayPartitionError(message);
		return;
	}

	if (diskSystem.IsFileSystem()) {
		if (disk->ID() == selectedPartition) {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to format a raw disk? (most people initialize the disk "
				"with a partitioning system first) You will be asked "
				"again before changes are written to the disk."));
		} else if (partition->ContentName()
			&& strlen(partition->ContentName()) > 0) {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to format the partition \"%s\"? You will be asked "
				"again before changes are written to the disk."),
				partition->ContentName());
		} else {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to format the partition? You will be asked again "
				"before changes are written to the disk."));
		}
	} else {
		snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
			"want to initialize the selected disk? All data will be lost. "
			"You will be asked again before changes are written to the "
			"disk.\n"));
	}
	BAlert* alert = new BAlert("first notice", message,
		B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL,
		B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
	int32 choice = alert->Go();

	if (choice == 1)
		return;

	ModificationPreparer modificationPreparer(disk);
	status_t ret = modificationPreparer.ModificationStatus();
	if (ret != B_OK) {
		_DisplayPartitionError(B_TRANSLATE("There was an error preparing the "
			"disk for modifications."), NULL, ret);
		return;
	}

	BString name;
	BString parameters;

	// TODO: diskSystem.IsFileSystem() seems like a better fit here?
	if (diskSystemName == "Be File System") {
		InitParamsPanel* panel = new InitParamsPanel(this, diskSystemName,
			partition);
		if (panel->Go(name, parameters) == GO_CANCELED)
			return;
	} else if (diskSystemName == "Intel Partition Map") {
		// TODO: parameters?
	} else if (diskSystemName == "Intel Extended Partition") {
		// TODO: parameters?
	}

	bool supportsName = diskSystem.SupportsContentName();
	BString validatedName(name);
	ret = partition->ValidateInitialize(diskSystem.PrettyName(),
		supportsName ? &validatedName : NULL, parameters.String());
	if (ret != B_OK) {
		_DisplayPartitionError(B_TRANSLATE("Validation of the given "
			"initialization parameters failed."), partition, ret);
		return;
	}

	BString previousName = partition->ContentName();

	ret = partition->Initialize(diskSystem.PrettyName(),
		supportsName ? validatedName.String() : NULL, parameters.String());
	if (ret != B_OK) {
		_DisplayPartitionError(B_TRANSLATE("Initialization of the partition "
			"%s failed. (Nothing has been written to disk.)"), partition, ret);
		return;
	}

	// everything looks fine, we are ready to actually write the changes
	// to disk

	// Warn the user one more time...
	if (previousName.Length() > 0) {
		if (partition->IsDevice()) {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to write the changes back to disk now?\n\n"
				"All data on the disk %s will be irretrievably lost if you "
				"do so!"), previousName.String());
		} else {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to write the changes back to disk now?\n\n"
				"All data on the partition %s will be irretrievably lost if you "
				"do so!"), previousName.String());
		}
	} else {
		if (partition->IsDevice()) {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to write the changes back to disk now?\n\n"
				"All data on the selected disk will be irretrievably lost if "
				"you do so!"));
		} else {
			snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you "
				"want to write the changes back to disk now?\n\n"
				"All data on the selected partition will be irretrievably lost "
				"if you do so!"));
		}
	}
	alert = new BAlert("final notice", message,
		B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL,
		B_WIDTH_FROM_WIDEST, B_WARNING_ALERT);
	choice = alert->Go();

	if (choice == 1)
		return;

	// commit
	ret = modificationPreparer.CommitModifications();

	// The partition pointer is toast now! Use the partition ID to
	// retrieve it again.
	partition = disk->FindDescendant(selectedPartition);

	if (ret == B_OK) {
		if (diskSystem.IsFileSystem()) {
			_DisplayPartitionError(B_TRANSLATE("The partition %s has been "
				"successfully formatted.\n"), partition);
		} else {
			_DisplayPartitionError(B_TRANSLATE("The disk has been "
				"successfully initialized.\n"), partition);
		}
	} else {
		if (diskSystem.IsFileSystem()) {
			_DisplayPartitionError(B_TRANSLATE("Failed to format the "
				"partition %s!\n"), partition, ret);
		} else {
			_DisplayPartitionError(B_TRANSLATE("Failed to initialize the "
				"disk %s!\n"), partition, ret);
		}
	}

	_ScanDrives();
}
Example #7
0
void
MainWindow::_UpdateMenus(BDiskDevice* disk,
	partition_id selectedPartition, partition_id parentID)
{
	while (BMenuItem* item = fFormatMenu->RemoveItem(0L))
		delete item;
	while (BMenuItem* item = fDiskInitMenu->RemoveItem(0L))
		delete item;

	fCreateMI->SetEnabled(false);
	fUnmountMI->SetEnabled(false);
	fDiskInitMenu->SetEnabled(false);
	fFormatMenu->SetEnabled(false);

	if (!disk) {
		fWipeMI->SetEnabled(false);
		fEjectMI->SetEnabled(false);
		fSurfaceTestMI->SetEnabled(false);
	} else {
//		fWipeMI->SetEnabled(true);
		fWipeMI->SetEnabled(false);
		fEjectMI->SetEnabled(disk->IsRemovableMedia());
//		fSurfaceTestMI->SetEnabled(true);
		fSurfaceTestMI->SetEnabled(false);

		// Create menu and items
		BPartition* parentPartition = NULL;
		if (selectedPartition <= -2) {
			// a partitionable space item is selected
			parentPartition = disk->FindDescendant(parentID);
		}

		if (parentPartition && parentPartition->ContainsPartitioningSystem())
			fCreateMI->SetEnabled(true);

		bool prepared = disk->PrepareModifications() == B_OK;
		fFormatMenu->SetEnabled(prepared);
		fDeleteMI->SetEnabled(prepared);

		BPartition* partition = disk->FindDescendant(selectedPartition);

		BDiskSystem diskSystem;
		fDDRoster.RewindDiskSystems();
		while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) {
			if (!diskSystem.SupportsInitializing())
				continue;

			BMessage* message = new BMessage(MSG_INITIALIZE);
			message->AddInt32("parent id", parentID);
			message->AddString("disk system", diskSystem.PrettyName());

			BString label = diskSystem.PrettyName();
			label << B_UTF8_ELLIPSIS;
			BMenuItem* item = new BMenuItem(label.String(), message);

			// TODO: Very unintuitive that we have to use PrettyName (vs Name)
			item->SetEnabled(partition != NULL
				&& partition->CanInitialize(diskSystem.PrettyName()));

			if (disk->ID() == selectedPartition
				&& !diskSystem.IsFileSystem()) {
				// Disk is selected, and DiskSystem is a partition map
				fDiskInitMenu->AddItem(item);
			} else if (diskSystem.IsFileSystem()) {
				// Otherwise a filesystem
				fFormatMenu->AddItem(item);
			}
		}

		// Mount items
		if (partition) {
			fFormatMenu->SetEnabled(!partition->IsMounted()
				&& !partition->IsReadOnly()
				&& partition->Device()->HasMedia()
				&& fFormatMenu->CountItems() > 0);

			fDiskInitMenu->SetEnabled(!partition->IsMounted()
				&& !partition->IsReadOnly()
				&& partition->Device()->HasMedia()
				&& partition->IsDevice()
				&& fDiskInitMenu->CountItems() > 0);

			fDeleteMI->SetEnabled(!partition->IsMounted()
				&& !partition->IsDevice());

			fMountMI->SetEnabled(!partition->IsMounted());

			bool unMountable = false;
			if (partition->IsMounted()) {
				// see if this partition is the boot volume
				BVolume volume;
				BVolume bootVolume;
				if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK
					&& partition->GetVolume(&volume) == B_OK) {
					unMountable = volume != bootVolume;
				} else
					unMountable = true;
			}
			fUnmountMI->SetEnabled(unMountable);
		} else {
			fDeleteMI->SetEnabled(false);
			fMountMI->SetEnabled(false);
			fFormatMenu->SetEnabled(false);
			fDiskInitMenu->SetEnabled(false);
		}

		if (prepared)
			disk->CancelModifications();

		fMountAllMI->SetEnabled(true);
	}
	if (selectedPartition < 0) {
		fDeleteMI->SetEnabled(false);
		fMountMI->SetEnabled(false);
	}
}
Example #8
0
// main
int
main(int argc, const char *const *argv)
{
	kArgc = argc;
	kArgv = argv;

	if (argc < 2)
		print_usage_and_exit(true);

	// parameters
	const char **files = new const char*[argc];
	int fileCount = 0;
	bool dryRun = false;
	off_t startOffset = 0;

	// parse arguments
	for (int argi = 1; argi < argc;) {
		const char *arg = argv[argi++];

		if (arg[0] == '-') {
			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
				print_usage_and_exit(false);
			} else if (strcmp(arg, "--dry-run") == 0) {
				dryRun = true;
			} else if (strcmp(arg, "-alert") == 0) {
				// ignore
			} else if (strcmp(arg, "-full") == 0) {
				// ignore
			} else if (strcmp(arg, "--start-offset") == 0) {
				if (argi >= argc)
					print_usage_and_exit(true);
				startOffset = strtoll(argv[argi++], NULL, 0);
			} else if (strcmp(arg, "-safe") == 0) {
				fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n");
				exit(1);
			} else {
				print_usage_and_exit(true);
			}

		} else {
			files[fileCount++] = arg;
		}
	}

	// we need at least one file
	if (fileCount == 0)
		print_usage_and_exit(true);

	// read the boot code
	uint8 *bootCodeData = NULL;
#ifndef __ANTARES__
	bootCodeData = read_boot_code_data(argv[0]);
#else
	image_info info;
	if (find_own_image(&info) == B_OK)
		bootCodeData = read_boot_code_data(info.name);
#endif
	if (!bootCodeData) {
		fprintf(stderr, "Error: Failed to read \n");
		exit(1);
	}

	// iterate through the files and make them bootable
	status_t error;
	for (int i = 0; i < fileCount; i++) {
		const char *fileName = files[i];
		BEntry entry;
		error = entry.SetTo(fileName, true);
		if (error != B_OK) {
			fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
				fileName, strerror(error));
			exit(1);
		}

		// get stat to check the type of the file
		struct stat st;
		error = entry.GetStat(&st);
		if (error != B_OK) {
			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n",
				fileName, strerror(error));
			exit(1);
		}

		bool noPartition = false;
		int64 partitionOffset = 0;
		fs_info info;	// needs to be here (we use the device name later)
		if (S_ISDIR(st.st_mode)) {
			#if defined(__BEOS__) || defined(__ANTARES__)

				// a directory: get the device
				error = fs_stat_dev(st.st_dev, &info);
				if (error != B_OK) {
					fprintf(stderr, "Error: Failed to determine device for "
						"\"%s\": %s\n", fileName, strerror(error));
					exit(1);
				}

				fileName = info.device_name;

			#else

				(void)info;
				fprintf(stderr, "Error: Specifying directories not supported "
					"on this platform!\n");
				exit(1);

			#endif

		} else if (S_ISREG(st.st_mode)) {
			// a regular file: fine
			noPartition = true;
		} else if (S_ISCHR(st.st_mode)) {
			// character special: a device or partition under BeOS
			// or under FreeBSD
			#if !(defined(__BEOS__) || defined(__ANTARES__)) && !defined(ANTARES_HOST_PLATFORM_FREEBSD)

				fprintf(stderr, "Error: Character special devices not "
					"supported on this platform.\n");
				exit(1);

			#endif

			#ifdef ANTARES_HOST_PLATFORM_FREEBSD

				// chop off the trailing number
				int fileNameLen = strlen(fileName);
				int baseNameLen = -1;
				for (int k = fileNameLen - 1; k >= 0; k--) {
					if (!isdigit(fileName[k])) {
						baseNameLen = k + 1;
						break;
					}
				}

				// Remove de 's' from 'ad2s2' slice device (partition for DOS
				// users) to get 'ad2' base device
				baseNameLen--;

				if (baseNameLen < 0) {
					// only digits?
					fprintf(stderr, "Error: Failed to get base device name.\n");
					exit(1);
				}

				if (baseNameLen < fileNameLen) {
					// get base device name and partition index
					char baseDeviceName[B_PATH_NAME_LENGTH];
					int partitionIndex = atoi(fileName + baseNameLen + 1);
						// Don't forget the 's' of slice :)
					memcpy(baseDeviceName, fileName, baseNameLen);
					baseDeviceName[baseNameLen] = '\0';

					// open base device
					int baseFD = open(baseDeviceName, O_RDONLY);
					if (baseFD < 0) {
						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
							baseDeviceName, strerror(errno));
						exit(1);
					}

					// get device size
					int64 deviceSize;
					if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) {
						fprintf(stderr, "Error: Failed to get device geometry "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
						exit(1);
					}

					// parse the partition map
					// TODO: block size!
					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
					PartitionMap map;
					error = parser.Parse(NULL, &map);
					if (error != B_OK) {
						fprintf(stderr, "Error: Parsing partition table on "
							"device \"%s\" failed: %s\n", baseDeviceName,
							strerror(error));
						exit(1);
					}

					close(baseFD);

					// check the partition we are supposed to write at
					Partition *partition = map.PartitionAt(partitionIndex - 1);
					if (!partition || partition->IsEmpty()) {
						fprintf(stderr, "Error: Invalid partition index %d.\n",
							partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					if (partition->IsExtended()) {
						fprintf(stderr, "Error: Partition %d is an extended "
							"partition.\n", partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					partitionOffset = partition->Offset();

				} else {
					// The given device is the base device. We'll write at
					// offset 0.
				}

			#endif // ANTARES_HOST_PLATFORM_FREEBSD

		} else if (S_ISBLK(st.st_mode)) {
			// block device: a device or partition under Linux or Darwin
			#ifdef ANTARES_HOST_PLATFORM_LINUX

				// chop off the trailing number
				int fileNameLen = strlen(fileName);
				int baseNameLen = -1;
				for (int k = fileNameLen - 1; k >= 0; k--) {
					if (!isdigit(fileName[k])) {
						baseNameLen = k + 1;
						break;
					}
				}

				if (baseNameLen < 0) {
					// only digits?
					fprintf(stderr, "Error: Failed to get base device name.\n");
					exit(1);
				}

				if (baseNameLen < fileNameLen) {
					// get base device name and partition index
					char baseDeviceName[B_PATH_NAME_LENGTH];
					int partitionIndex = atoi(fileName + baseNameLen);
					memcpy(baseDeviceName, fileName, baseNameLen);
					baseDeviceName[baseNameLen] = '\0';

					// open base device
					int baseFD = open(baseDeviceName, O_RDONLY);
					if (baseFD < 0) {
						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
							baseDeviceName, strerror(errno));
						exit(1);
					}

					// get device size -- try BLKGETSIZE64, but, if it doesn't
					// work, fall back to the obsolete HDIO_GETGEO
					int64 deviceSize;
					hd_geometry geometry;
					if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0
						&& deviceSize > 0) {
						// looks good
					} else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) {
						deviceSize = (int64)geometry.heads * geometry.sectors
							* geometry.cylinders * 512;
					} else {
						fprintf(stderr, "Error: Failed to get device geometry "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
						exit(1);
					}

					// parse the partition map
					// TODO: block size!
					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
					PartitionMap map;
					error = parser.Parse(NULL, &map);
					if (error != B_OK) {
						fprintf(stderr, "Error: Parsing partition table on "
							"device \"%s\" failed: %s\n", baseDeviceName,
							strerror(error));
						exit(1);
					}

					close(baseFD);

					// check the partition we are supposed to write at
					Partition *partition = map.PartitionAt(partitionIndex - 1);
					if (!partition || partition->IsEmpty()) {
						fprintf(stderr, "Error: Invalid partition index %d.\n",
							partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					if (partition->IsExtended()) {
						fprintf(stderr, "Error: Partition %d is an extended "
							"partition.\n", partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					partitionOffset = partition->Offset();
				} else {
					// The given device is the base device. We'll write at
					// offset 0.
				}

			#elif defined(ANTARES_HOST_PLATFORM_DARWIN)
				// chop off the trailing number
				int fileNameLen = strlen(fileName);
				int baseNameLen = fileNameLen - 2;

				// get base device name and partition index
				char baseDeviceName[B_PATH_NAME_LENGTH];
				int partitionIndex = atoi(fileName + baseNameLen + 1);
				memcpy(baseDeviceName, fileName, baseNameLen);
				baseDeviceName[baseNameLen] = '\0';

				// open base device
				int baseFD = open(baseDeviceName, O_RDONLY);
				if (baseFD < 0) {
					fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
							baseDeviceName, strerror(errno));
					exit(1);
				}

				// get device size
				int64 blockSize;
				int64 blockCount;
				int64 deviceSize;
				if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) {
					fprintf(stderr, "Error: Failed to get block size "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
					exit(1);
				}
				if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) {
					fprintf(stderr, "Error: Failed to get block count "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
					exit(1);
				}

				deviceSize = blockSize * blockCount;

				// parse the partition map
				PartitionMapParser parser(baseFD, 0, deviceSize, blockSize);
				PartitionMap map;
				error = parser.Parse(NULL, &map);
				if (error != B_OK) {
					fprintf(stderr, "Error: Parsing partition table on "
							"device \"%s\" failed: %s\n", baseDeviceName,
							strerror(error));
					exit(1);
				}

				close(baseFD);

				// check the partition we are supposed to write at
				Partition *partition = map.PartitionAt(partitionIndex - 1);
				if (!partition || partition->IsEmpty()) {
					fprintf(stderr, "Error: Invalid partition index %d.\n",
						partitionIndex);
					dump_partition_map(map);
					exit(1);
				}

				if (partition->IsExtended()) {
					fprintf(stderr, "Error: Partition %d is an extended "
						"partition.\n", partitionIndex);
					dump_partition_map(map);
					exit(1);
				}
				partitionOffset = partition->Offset();
			#else
			// partitions are block devices under Antares, but not under BeOS
			#ifndef __ANTARES__
				fprintf(stderr, "Error: Block devices not supported on this "
					"platform!\n");
				exit(1);
			#endif	// __ANTARES__

			#endif
		} else {
			fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
				fileName);
			exit(1);
		}

		// open the file
		int fd = open(fileName, O_RDWR);
		if (fd < 0) {
			fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName,
				strerror(errno));
			exit(1);
		}

		#if (defined(__BEOS__) || defined(__ANTARES__))

			// get a partition info
			if (!noPartition
				&& strlen(fileName) >= 3
				&& strncmp("raw", fileName + strlen(fileName) - 3, 3)) {
				partition_info partitionInfo;
				if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
						sizeof(partitionInfo)) == 0) {
					partitionOffset = partitionInfo.offset;
				} else {
					fprintf(stderr, "Error: Failed to get partition info: %s\n",
						strerror(errno));
					exit(1);
				}
			}

		#endif	// __BEOS__

		// adjust the partition offset in the boot code data
		// hard coded sector size: 512 bytes
		*(uint32*)(bootCodeData + kPartitionOffsetOffset)
			= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));

		// write the boot code
		printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64
			" bytes, start offset = %" B_PRIdOFF ") "
			"...\n", fileName, partitionOffset, startOffset);

		write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0,
			kFirstBootCodePartSize, dryRun);
		write_boot_code_part(fileName, fd, startOffset, bootCodeData,
			kSecondBootCodePartOffset, kSecondBootCodePartSize,
			dryRun);

#ifdef __ANTARES__
		// check if this partition is mounted
		BDiskDeviceRoster roster;
		BPartition* partition;
		BDiskDevice device;
		status_t status = roster.GetPartitionForPath(fileName, &device,
			&partition);
		if (status != B_OK) {
			status = roster.GetFileDeviceForPath(fileName, &device);
			if (status == B_OK)
				partition = &device;
		}
		if (status == B_OK && partition->IsMounted() && !dryRun) {
			// This partition is mounted, we need to tell BFS to update its
			// boot block (we are using part of the same logical block).
			BPath path;
			status = partition->GetMountPoint(&path);
			if (status == B_OK) {
				update_boot_block update;
				update.offset = kSecondBootCodePartOffset - 512;
				update.data = bootCodeData + kSecondBootCodePartOffset;
				update.length = kSecondBootCodePartSize;

				int mountFD = open(path.Path(), O_RDONLY);
				if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update,
						sizeof(update_boot_block)) != 0) {
					fprintf(stderr, "Could not update BFS boot block: %s\n",
						strerror(errno));
				}
				close(mountFD);
			} else {
				fprintf(stderr, "Could not update BFS boot code while the "
					"partition is mounted!\n");
			}
		}
#endif	// __ANTARES__

		close(fd);
	}

	return 0;
}