status_t WorkerThread::_InstallationError(status_t error) { BMessage statusMessage(MSG_RESET); if (error == B_CANCELED) _SetStatusMessage(B_TRANSLATE("Installation canceled.")); else statusMessage.AddInt32("error", error); ERR("_PerformInstall failed"); fOwner.SendMessage(&statusMessage); return error; }
void WorkerThread::_LaunchFinishScript(BPath &path) { BPath bootPath; find_directory(B_BEOS_BOOT_DIRECTORY, &bootPath); BString command("/bin/sh "); command += bootPath.Path(); command += "/InstallerFinishScript "; command += "\""; command += path.Path(); command += "\""; _SetStatusMessage(B_TRANSLATE("Finishing Installation.")); system(command.String()); }
status_t WorkerThread::_LaunchInitScript(BPath &path) { BPath bootPath; find_directory(B_BEOS_BOOT_DIRECTORY, &bootPath); BString command("/bin/sh "); command += bootPath.Path(); command += "/InstallerInitScript "; command += "\""; command += path.Path(); command += "\""; _SetStatusMessage(B_TRANSLATE("Starting installation.")); return system(command.String()); }
void InstallerWindow::_ScanPartitions() { _SetStatusMessage(TR("Scanning for disks" B_UTF8_ELLIPSIS)); BMenuItem *item; while ((item = fSrcMenu->RemoveItem((int32)0))) delete item; while ((item = fDestMenu->RemoveItem((int32)0))) delete item; fWorkerThread->ScanDisksPartitions(fSrcMenu, fDestMenu); if (fSrcMenu->ItemAt(0)) { _PublishPackages(); } _UpdateControls(); }
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); } }
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); }
void InstallerWindow::_UpdateControls() { PartitionMenuItem* srcItem = (PartitionMenuItem*)fSrcMenu->FindMarked(); BString label; if (srcItem) { label = srcItem->MenuLabel(); } else { if (fSrcMenu->CountItems() == 0) label = TR_CMT("<none>", "No partition available"); else label = ((PartitionMenuItem*)fSrcMenu->ItemAt(0))->MenuLabel(); } fSrcMenuField->MenuItem()->SetLabel(label.String()); // Disable any unsuitable target items, check if at least one partition // is suitable. bool foundOneSuitableTarget = false; for (int32 i = fDestMenu->CountItems() - 1; i >= 0; i--) { PartitionMenuItem* dstItem = (PartitionMenuItem*)fDestMenu->ItemAt(i); if (srcItem != NULL && dstItem->ID() == srcItem->ID()) { // Prevent the user from having picked the same partition as source // and destination. dstItem->SetEnabled(false); dstItem->SetMarked(false); } else dstItem->SetEnabled(dstItem->IsValidTarget()); if (dstItem->IsEnabled()) foundOneSuitableTarget = true; } PartitionMenuItem* dstItem = (PartitionMenuItem*)fDestMenu->FindMarked(); if (dstItem) { label = dstItem->MenuLabel(); } else { if (fDestMenu->CountItems() == 0) label = TR_CMT("<none>", "No partition available"); else label = TR("Please choose target"); } fDestMenuField->MenuItem()->SetLabel(label.String()); if (srcItem && dstItem) { char message[255]; sprintf(message, TR("Press the Begin button to install from '%1s' " "onto '%2s'."), srcItem->Name(), dstItem->Name()); _SetStatusMessage(message); } else if (srcItem) { _SetStatusMessage(TR("Choose the disk you want to install onto from " "the pop-up menu. Then click \"Begin\".")); } else if (dstItem) { _SetStatusMessage(TR("Choose the source disk from the " "pop-up menu. Then click \"Begin\".")); } else { _SetStatusMessage(TR("Choose the source and destination disk from the " "pop-up menus. Then click \"Begin\".")); } fInstallStatus = kReadyForInstall; fBeginButton->SetLabel(TR("Begin")); fBeginButton->SetEnabled(srcItem && dstItem); // adjust "Write Boot Sector" button if (dstItem) { char buffer[256]; snprintf(buffer, sizeof(buffer), TR("Write boot sector to '%s'"), dstItem->Name()); label = buffer; } else label = TR("Write boot sector"); fMakeBootableButton->SetEnabled(dstItem); fMakeBootableButton->SetLabel(label.String()); if (!fEncouragedToSetupPartitions && !foundOneSuitableTarget) { // Focus the users attention on the DriveSetup button fEncouragedToSetupPartitions = true; PostMessage(ENCOURAGE_DRIVESETUP); } }
void InstallerWindow::MessageReceived(BMessage *msg) { switch (msg->what) { case MSG_RESET: { _SetCopyEngineCancelSemaphore(-1); status_t error; if (msg->FindInt32("error", &error) == B_OK) { char errorMessage[2048]; snprintf(errorMessage, sizeof(errorMessage), TR("An error was " "encountered and the installation was not completed:\n\n" "Error: %s"), strerror(error)); (new BAlert("error", errorMessage, TR("OK")))->Go(); } _DisableInterface(false); fProgressLayoutItem->SetVisible(false); fPkgSwitchLayoutItem->SetVisible(true); _ShowOptionalPackages(); _UpdateControls(); break; } case START_SCAN: _ScanPartitions(); break; case BEGIN_MESSAGE: switch (fInstallStatus) { case kReadyForInstall: { _SetCopyEngineCancelSemaphore(create_sem(1, "copy engine cancel")); BList* list = new BList(); int32 size = 0; fPackagesView->GetPackagesToInstall(list, &size); fWorkerThread->SetLock(fCopyEngineCancelSemaphore); fWorkerThread->SetPackagesList(list); fWorkerThread->SetSpaceRequired(size); fInstallStatus = kInstalling; fWorkerThread->StartInstall(); fBeginButton->SetLabel(TR("Stop")); _DisableInterface(true); fProgressBar->SetTo(0.0, NULL, NULL); fPkgSwitchLayoutItem->SetVisible(false); fPackagesLayoutItem->SetVisible(false); fSizeViewLayoutItem->SetVisible(false); fProgressLayoutItem->SetVisible(true); break; } case kInstalling: { _QuitCopyEngine(true); break; } case kFinished: PostMessage(B_QUIT_REQUESTED); break; case kCancelled: break; } break; case SHOW_BOTTOM_MESSAGE: _ShowOptionalPackages(); break; case SOURCE_PARTITION: _PublishPackages(); _UpdateControls(); break; case TARGET_PARTITION: _UpdateControls(); break; case SETUP_MESSAGE: _LaunchDriveSetup(); break; case PACKAGE_CHECKBOX: { char buffer[15]; fPackagesView->GetTotalSizeAsString(buffer); char string[255]; sprintf(string, TR("Additional disk space required: %s"), buffer); fSizeView->SetText(string); break; } case ENCOURAGE_DRIVESETUP: { (new BAlert("use drive setup", TR("No partitions have been found " "that are suitable for installation. Please set up partitions " "and initialize at least one partition with the Be File " "System."), TR("OK")))->Go(); } case MSG_STATUS_MESSAGE: { // TODO: Was this supposed to prevent status messages still arriving // after the copy engine was shut down? // if (fInstallStatus != kInstalling) // break; float progress; if (msg->FindFloat("progress", &progress) == B_OK) { const char* currentItem; if (msg->FindString("item", ¤tItem) != B_OK) { currentItem = TR_CMT("???", "Unknown currently copied item"); } BString trailingLabel; int32 currentCount; int32 maximumCount; if (msg->FindInt32("current", ¤tCount) == B_OK && msg->FindInt32("maximum", &maximumCount) == B_OK) { char buffer[64]; snprintf(buffer, sizeof(buffer), TR_CMT("%1ld of %2ld", "number of files copied"), currentCount, maximumCount); trailingLabel << buffer; } else { trailingLabel << TR_CMT("?? of ??", "Unknown progress"); } fProgressBar->SetTo(progress, currentItem, trailingLabel.String()); } else { const char *status; if (msg->FindString("status", &status) == B_OK) { fLastStatus = fStatusView->Text(); _SetStatusMessage(status); } else _SetStatusMessage(fLastStatus.String()); } break; } case MSG_INSTALL_FINISHED: { _SetCopyEngineCancelSemaphore(-1); fBeginButton->SetLabel(TR("Quit")); PartitionMenuItem* dstItem = (PartitionMenuItem*)fDestMenu->FindMarked(); char status[1024]; if (be_roster->IsRunning(kDeskbarSignature)) { snprintf(status, sizeof(status), TR("Installation completed. " "Boot sector has been written to '%s'. Press Quit to " "leave the Installer or choose a new target volume to " "perform another installation."), dstItem ? dstItem->Name() : TR_CMT("???", "Unknown partition name")); } else { snprintf(status, sizeof(status), TR("Installation completed. " "Boot sector has been written to '%s'. Press Quit to " "restart the computer or choose a new target volume " "to perform another installation."), dstItem ? dstItem->Name() : TR_CMT("???", "Unknown partition name")); } _SetStatusMessage(status); fInstallStatus = kFinished; _DisableInterface(false); fProgressLayoutItem->SetVisible(false); fPkgSwitchLayoutItem->SetVisible(true); _ShowOptionalPackages(); break; } case B_SOME_APP_LAUNCHED: case B_SOME_APP_QUIT: { const char *signature; if (msg->FindString("be:signature", &signature) == B_OK && strcasecmp(signature, DRIVESETUP_SIG) == 0) { fDriveSetupLaunched = msg->what == B_SOME_APP_LAUNCHED; fBeginButton->SetEnabled(!fDriveSetupLaunched); _DisableInterface(fDriveSetupLaunched); if (fDriveSetupLaunched) _SetStatusMessage(TR("Running DriveSetup" B_UTF8_ELLIPSIS "\n\nClose DriveSetup to continue with the " "installation.")); else _ScanPartitions(); } break; } case MSG_WRITE_BOOT_SECTOR: fWorkerThread->WriteBootSector(fDestMenu); break; default: BWindow::MessageReceived(msg); break; } }