/*!	\brief Pre-order traverses the trees spanned by the BDiskDevices and their
		   subobjects.

	The supplied visitor's Visit(BDiskDevice*) method is invoked for each
	disk device and Visit(BPartition*) for each (non-disk device) partition.
	If Visit() returns \c true, the iteration is terminated and this method
	returns \c true. If supplied, \a device is set to the concerned device
	and in \a partition the pointer to the partition object is returned.

	\param visitor The visitor.
	\param device Pointer to a pre-allocated BDiskDevice to be initialized
		   to the device at which the iteration was terminated.
		   May be \c NULL.
	\param partition Pointer to a pre-allocated BPartition pointer to be set
		   to the partition at which the iteration was terminated.
		   May be \c NULL.
	\return \c true, if the iteration was terminated, \c false otherwise.
*/
bool
BDiskDeviceRoster::VisitEachPartition(BDiskDeviceVisitor* visitor,
	BDiskDevice* device, BPartition** partition)
{
	bool terminatedEarly = false;
	if (visitor) {
		int32 oldCookie = fDeviceCookie;
		fDeviceCookie = 0;
		BDiskDevice deviceOnStack;
		BDiskDevice* useDevice = device ? device : &deviceOnStack;
		BPartition* foundPartition = NULL;
		while (GetNextDevice(useDevice) == B_OK) {
			foundPartition = useDevice->VisitEachDescendant(visitor);
			if (foundPartition) {
				terminatedEarly = true;
				break;
			}
		}
		fDeviceCookie = oldCookie;
		if (!terminatedEarly)
			useDevice->Unset();
		else if (device && partition)
			*partition = foundPartition;
	}
	return terminatedEarly;
}
Exemple #2
0
void
MainWindow::_SetToDiskAndPartition(partition_id disk, partition_id partition,
	partition_id parent)
{
//printf("MainWindow::_SetToDiskAndPartition(disk: %ld, partition: %ld, "
//	"parent: %ld)\n", disk, partition, parent);

	BDiskDevice* oldDisk = NULL;
	if (!fCurrentDisk || fCurrentDisk->ID() != disk) {
		oldDisk = fCurrentDisk;
		fCurrentDisk = NULL;
		if (disk >= 0) {
			BDiskDevice* newDisk = new BDiskDevice();
			status_t ret = newDisk->SetTo(disk);
			if (ret < B_OK) {
				printf("error switching disks: %s\n", strerror(ret));
				delete newDisk;
			} else
				fCurrentDisk = newDisk;
		}
	}

	fCurrentPartitionID = partition;

	fDiskView->SetDisk(fCurrentDisk, fCurrentPartitionID);
	_UpdateMenus(fCurrentDisk, fCurrentPartitionID, parent);

	delete oldDisk;
}
/*!	\brief Iterates through the all devices.

	The supplied visitor's Visit(BDiskDevice*) is invoked for each device.
	If Visit() returns \c true, the iteration is terminated and this method
	returns \c true. If supplied, \a device is set to the concerned device.

	\param visitor The visitor.
	\param device Pointer to a pre-allocated BDiskDevice to be initialized
		   to the device at which the iteration was terminated.
		   May be \c NULL.
	\return \c true, if the iteration was terminated, \c false otherwise.
*/
bool
BDiskDeviceRoster::VisitEachDevice(BDiskDeviceVisitor* visitor,
	BDiskDevice* device)
{
	bool terminatedEarly = false;
	if (visitor) {
		int32 oldCookie = fDeviceCookie;
		fDeviceCookie = 0;
		BDiskDevice deviceOnStack;
		BDiskDevice* useDevice = device ? device : &deviceOnStack;
		while (!terminatedEarly && GetNextDevice(useDevice) == B_OK)
			terminatedEarly = visitor->Visit(useDevice);
		fDeviceCookie = oldCookie;
		if (!terminatedEarly)
			useDevice->Unset();
	}
	return terminatedEarly;
}
Exemple #4
0
DriveItem::DriveItem(const BDiskDevice& device, const BootMenuList& menus)
	:
	fBaselineOffset(0),
	fSizeWidth(0)
{
	device.GetPath(&fPath);
	if (device.Name() != NULL && device.Name()[0])
		fName = device.Name();
	else if (strstr(fPath.Path(), "usb") != NULL)
		fName = B_TRANSLATE_COMMENT("USB Drive", "Default disk name");
	else
		fName = B_TRANSLATE_COMMENT("Hard Drive", "Default disk name");

	fIcon = new BBitmap(BRect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1),
		B_RGBA32);
	if (device.GetIcon(fIcon, B_LARGE_ICON) != B_OK)
		memset(fIcon->Bits(), 0, fIcon->BitsLength());

	fDrive = new BootDrive(fPath.Path());

	fIsInstalled = fDrive->InstalledMenu(menus) != NULL;
	fCanBeInstalled = fDrive->CanMenuBeInstalled(menus);

	char buffer[256];
	fSize = string_for_size(device.Size(), buffer, sizeof(buffer));
}
Exemple #5
0
/*!	Builds the list view items, and adds them to fDriveView.
	Sets the fHasInstallableItems member to indicate if there
	are any possible install targets. Automatically
	selects the boot drive.
*/
void
DrivesPage::_FillDrivesView(const BootMenuList& menus)
{
	const char* selected = fSettings->FindString("disk");

	BDiskDeviceRoster roster;
	BDiskDevice device;
	while (roster.GetNextDevice(&device) == B_OK) {
		if (device.HasMedia() && !device.IsReadOnly()) {
			DriveItem* item = new DriveItem(device, menus);
			if (item->CanBeInstalled())
				fHasInstallableItems = true;
			fDrivesView->AddItem(item);

			if ((selected == NULL && item->IsBootDrive())
				|| (selected != NULL && !strcmp(item->Path(), selected))) {
				fDrivesView->Select(fDrivesView->CountItems() - 1);
				_UpdateWizardButtons(item);
			}
		}
	}
}
Exemple #6
0
void
InstallerWindow::_PublishPackages()
{
	fPackagesView->Clean();
	PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked();
	if (!item)
		return;

	BPath directory;
	BDiskDeviceRoster roster;
	BDiskDevice device;
	BPartition *partition;
	if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) {
		if (partition->GetMountPoint(&directory) != B_OK)
			return;
	} else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) {
		if (device.GetMountPoint(&directory) != B_OK)
			return;
	} else
		return; // shouldn't happen

	directory.Append(PACKAGES_DIRECTORY);
	BDirectory dir(directory.Path());
	if (dir.InitCheck() != B_OK)
		return;

	BEntry packageEntry;
	BList packages;
	while (dir.GetNextEntry(&packageEntry) == B_OK) {
		Package* package = Package::PackageFromEntry(packageEntry);
		if (package != NULL)
			packages.AddItem(package);
	}
	packages.SortItems(_ComparePackages);

	fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX));
	PostMessage(PACKAGE_CHECKBOX);
}
Exemple #7
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);
	}
}
Exemple #8
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);
}
Exemple #9
0
void
AutoMounter::_UnmountAndEjectVolume(BPartition* partition, BPath& mountPoint,
	const char* name)
{
	BDiskDevice deviceStorage;
	BDiskDevice* device;
	if (partition == NULL) {
		// Try to retrieve partition
		BDiskDeviceRoster().FindPartitionByMountPoint(mountPoint.Path(),
			&deviceStorage, &partition);
			device = &deviceStorage;
	} else {
		device = partition->Device();
	}

	status_t status;
	if (partition != NULL)
		status = partition->Unmount();
	else
		status = fs_unmount_volume(mountPoint.Path(), 0);

	if (status != B_OK) {
		if (!_SuggestForceUnmount(name, status))
			return;

		if (partition != NULL)
			status = partition->Unmount(B_FORCE_UNMOUNT);
		else
			status = fs_unmount_volume(mountPoint.Path(), B_FORCE_UNMOUNT);
	}

	if (status != B_OK) {
		_ReportUnmountError(name, status);
		return;
	}

	if (fEjectWhenUnmounting && partition != NULL) {
		// eject device if it doesn't have any mounted partitions left
		class IsMountedVisitor : public BDiskDeviceVisitor {
		public:
			IsMountedVisitor()
				:
				fHasMounted(false)
			{
			}

			virtual bool Visit(BDiskDevice* device)
			{
				return Visit(device, 0);
			}

			virtual bool Visit(BPartition* partition, int32 level)
			{
				if (partition->IsMounted()) {
					fHasMounted = true;
					return true;
				}

				return false;
			}

			bool HasMountedPartitions() const
			{
				return fHasMounted;
			}

		private:
			bool	fHasMounted;
		} visitor;

		device->VisitEachDescendant(&visitor);

		if (!visitor.HasMountedPartitions())
			device->Eject();
	}

	// remove the directory if it's a directory in rootfs
	if (dev_for_path(mountPoint.Path()) == dev_for_path("/"))
		rmdir(mountPoint.Path());
}
Exemple #10
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;
}