diff --git a/headers/private/kernel/boot/kernel_args.h b/headers/private/kernel/boot/kernel_args.h index 6f608641b3..9a6a45568d 100644 --- a/headers/private/kernel/boot/kernel_args.h +++ b/headers/private/kernel/boot/kernel_args.h @@ -29,6 +29,7 @@ #define BOOT_VOLUME_USER_SELECTED "user selected" #define BOOT_VOLUME_BOOTED_FROM_IMAGE "booted from image" #define BOOT_VOLUME_PACKAGED "packaged" +#define BOOT_VOLUME_PACKAGES_STATE "packages state" #define BOOT_VOLUME_PARTITION_OFFSET "partition offset" #define BOOT_VOLUME_DISK_IDENTIFIER "disk identifier" diff --git a/headers/private/kernel/boot/vfs.h b/headers/private/kernel/boot/vfs.h index 631d7dc773..f33f5e7884 100644 --- a/headers/private/kernel/boot/vfs.h +++ b/headers/private/kernel/boot/vfs.h @@ -18,6 +18,8 @@ struct file_map_run; struct stat; +class PackageVolumeInfo; +class PackageVolumeState; /** This is the base class for all VFS nodes */ @@ -114,7 +116,11 @@ public: BootVolume(); ~BootVolume(); - status_t SetTo(Directory* rootDirectory); + status_t SetTo(Directory* rootDirectory, + PackageVolumeInfo* packageVolumeInfo + = NULL, + PackageVolumeState* packageVolumeState + = NULL); void Unset(); bool IsValid() const @@ -125,9 +131,16 @@ public: Directory* SystemDirectory() const { return fSystemDirectory; } bool IsPackaged() const - { return fPackaged; } + { return fPackageVolumeInfo != NULL; } + PackageVolumeInfo* GetPackageVolumeInfo() const + { return fPackageVolumeInfo; } + PackageVolumeState* GetPackageVolumeState() const + { return fPackageVolumeState; } private: + status_t _SetTo(Directory* rootDirectory, + PackageVolumeInfo* packageVolumeInfo, + PackageVolumeState* packageVolumeState); int _OpenSystemPackage(); private: @@ -136,8 +149,8 @@ private: Directory* fSystemDirectory; // "system" directory of the volume; if packaged the root // directory of the mounted packagefs - bool fPackaged; - // indicates whether the boot volume's system is packaged + PackageVolumeInfo* fPackageVolumeInfo; + PackageVolumeState* fPackageVolumeState; }; diff --git a/src/system/boot/loader/Jamfile b/src/system/boot/loader/Jamfile index 1f2b0bded4..324423ad25 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -64,6 +64,7 @@ BootStaticLibrary boot_loader : loader.cpp main.cpp menu.cpp + package_support.cpp pager.cpp partitions.cpp RootFileSystem.cpp diff --git a/src/system/boot/loader/menu.cpp b/src/system/boot/loader/menu.cpp index 5de8c16129..9e2ce912dd 100644 --- a/src/system/boot/loader/menu.cpp +++ b/src/system/boot/loader/menu.cpp @@ -1,7 +1,7 @@ /* * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de. * Copyright 2011, Rene Gollent, rene@gollent.com. - * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -31,6 +31,7 @@ #include "load_driver_settings.h" #include "loader.h" +#include "package_support.h" #include "pager.h" #include "RootFileSystem.h" @@ -764,6 +765,77 @@ public: }; +// #pragma mark - boot volume menu + + +class BootVolumeMenuItem : public MenuItem { +public: + BootVolumeMenuItem(const char* volumeName) + : + MenuItem(volumeName), + fStateChoiceText(NULL) + { + } + + ~BootVolumeMenuItem() + { + UpdateStateName(NULL); + } + + void UpdateStateName(PackageVolumeState* volumeState) + { + free(fStateChoiceText); + fStateChoiceText = NULL; + + if (volumeState != NULL && volumeState->Name() != NULL) { + char nameBuffer[128]; + snprintf(nameBuffer, sizeof(nameBuffer), "%s (%s)", Label(), + volumeState->DisplayName()); + fStateChoiceText = strdup(nameBuffer); + } + + Supermenu()->SetChoiceText( + fStateChoiceText != NULL ? fStateChoiceText : Label()); + } + +private: + char* fStateChoiceText; +}; + + +class PackageVolumeStateMenuItem : public MenuItem { +public: + PackageVolumeStateMenuItem(const char* label, PackageVolumeInfo* volumeInfo, + PackageVolumeState* volumeState) + : + MenuItem(label), + fVolumeInfo(volumeInfo), + fVolumeState(volumeState) + { + fVolumeInfo->AcquireReference(); + } + + ~PackageVolumeStateMenuItem() + { + fVolumeInfo->ReleaseReference(); + } + + PackageVolumeInfo* VolumeInfo() const + { + return fVolumeInfo; + } + + PackageVolumeState* VolumeState() const + { + return fVolumeState; + } + +private: + PackageVolumeInfo* fVolumeInfo; + PackageVolumeState* fVolumeState; +}; + + // #pragma mark - @@ -876,6 +948,42 @@ user_menu_boot_volume(Menu* menu, MenuItem* item) } +static bool +user_menu_boot_volume_state(Menu* menu, MenuItem* _item) +{ + MenuItem* bootItem = get_continue_booting_menu_item(); + if (bootItem == NULL) { + // huh? + return true; + } + + PackageVolumeStateMenuItem* item = static_cast( + _item); + if (sBootVolume->IsValid() && sBootVolume->GetPackageVolumeState() != NULL + && sBootVolume->GetPackageVolumeState() == item->VolumeState()) { + return true; + } + + BootVolumeMenuItem* volumeItem = static_cast( + item->Supermenu()->Superitem()); + volumeItem->SetMarked(true); + volumeItem->Select(true); + volumeItem->UpdateStateName(item->VolumeState()); + + sPathBlacklist->MakeEmpty(); + + bool valid = sBootVolume->SetTo((Directory*)item->Data(), + item->VolumeInfo(), item->VolumeState()) == B_OK; + + bootItem->SetEnabled(valid); + if (valid) + bootItem->Select(true); + + gBootVolume.SetBool(BOOT_VOLUME_USER_SELECTED, true); + return true; +} + + static bool debug_menu_display_current_log(Menu* menu, MenuItem* item) { @@ -1060,8 +1168,65 @@ debug_menu_save_previous_syslog(Menu* menu, MenuItem* item) } +static void +add_boot_volume_item(Menu* menu, Directory* volume, const char* name) +{ + BReference volumeInfo; + PackageVolumeState* selectedState = NULL; + if (volume == sBootVolume->RootDirectory()) { + volumeInfo.SetTo(sBootVolume->GetPackageVolumeInfo()); + selectedState = sBootVolume->GetPackageVolumeState(); + } else { + volumeInfo.SetTo(new(std::nothrow) PackageVolumeInfo); + if (volumeInfo->SetTo(volume, "system/packages") == B_OK) + selectedState = volumeInfo->States().Head(); + else + volumeInfo.Unset(); + } + + BootVolumeMenuItem* item = new(nothrow) BootVolumeMenuItem(name); + menu->AddItem(item); + + Menu* subMenu = NULL; + + if (volumeInfo != NULL) { + subMenu = new(std::nothrow) Menu(CHOICE_MENU, "Select Haiku version"); + + for (PackageVolumeStateList::ConstIterator it + = volumeInfo->States().GetIterator(); + PackageVolumeState* state = it.Next();) { + PackageVolumeStateMenuItem* stateItem + = new(nothrow) PackageVolumeStateMenuItem(state->DisplayName(), + volumeInfo, state); + subMenu->AddItem(stateItem); + stateItem->SetTarget(user_menu_boot_volume_state); + stateItem->SetData(volume); + + if (state == selectedState) { + stateItem->SetMarked(true); + stateItem->Select(true); + item->UpdateStateName(stateItem->VolumeState()); + } + } + } + + if (subMenu != NULL && subMenu->CountItems() > 1) { + item->SetSubmenu(subMenu); + } else { + delete subMenu; + item->SetTarget(user_menu_boot_volume); + item->SetData(volume); + } + + if (volume == sBootVolume->RootDirectory()) { + item->SetMarked(true); + item->Select(true); + } +} + + static Menu* -add_boot_volume_menu(Directory* bootVolume) +add_boot_volume_menu() { Menu* menu = new(std::nothrow) Menu(CHOICE_MENU, "Select Boot Volume"); MenuItem* item; @@ -1072,19 +1237,12 @@ add_boot_volume_menu(Directory* bootVolume) Directory* volume; while (gRoot->GetNextNode(cookie, (Node**)&volume) == B_OK) { // only list bootable volumes - if (volume != bootVolume && !is_bootable(volume)) + if (volume != sBootVolume->RootDirectory() && !is_bootable(volume)) continue; char name[B_FILE_NAME_LENGTH]; if (volume->GetName(name, sizeof(name)) == B_OK) { - menu->AddItem(item = new(nothrow) MenuItem(name)); - item->SetTarget(user_menu_boot_volume); - item->SetData(volume); - - if (volume == bootVolume) { - item->SetMarked(true); - item->Select(true); - } + add_boot_volume_item(menu, volume, name); count++; } @@ -1425,7 +1583,7 @@ user_menu(BootVolume& _bootVolume, PathBlacklist& _pathBlacklist) // Add boot volume menu->AddItem(item = new(std::nothrow) MenuItem("Select boot volume", - add_boot_volume_menu(_bootVolume.RootDirectory()))); + add_boot_volume_menu())); // Add safe mode menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options", diff --git a/src/system/boot/loader/package_support.cpp b/src/system/boot/loader/package_support.cpp new file mode 100644 index 0000000000..30f9fcdd6e --- /dev/null +++ b/src/system/boot/loader/package_support.cpp @@ -0,0 +1,351 @@ +/* + * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "package_support.h" + +#include +#include +#include + +#include +#include +#include + + +#define TRACE_PACKAGE_SUPPORT +#ifdef TRACE_PACKAGE_SUPPORT +# define TRACE(...) dprintf(__VA_ARGS__) +#else +# define TRACE(...) do {} while (false) +#endif + +static const char* const kAdministrativeDirectory + = PACKAGES_DIRECTORY_ADMIN_DIRECTORY; +static const char* const kActivatedPackagesFile + = PACKAGES_DIRECTORY_ACTIVATION_FILE; + + +static inline bool +is_system_package(const char* name) +{ + // The name must end with ".hpkg". + size_t nameLength = strlen(name); + if (nameLength < 6 || strcmp(name + nameLength - 5, ".hpkg") != 0) + return false; + + // The name must either be "haiku.hpkg" or start with "haiku-". + return strcmp(name, "haiku.hpkg") == 0 || strncmp(name, "haiku-", 6) == 0; +} + + +// #pragma mark - PackageVolumeState + + +PackageVolumeState::PackageVolumeState() + : + fName(NULL), + fDisplayName(NULL), + fSystemPackage(NULL) +{ +} + + +PackageVolumeState::~PackageVolumeState() +{ + Unset(); +} + + +status_t +PackageVolumeState::SetTo(const char* stateName) +{ + Unset(); + + if (stateName != NULL) { + fName = strdup(stateName); + if (fName == NULL) + return B_NO_MEMORY; + + // Derive the display name from the directory name: Chop off the leading + // "state_" and replace underscores by spaces. + fDisplayName = strncmp(stateName, "state_", 6) == 0 + ? strdup(stateName + 6) : strdup(stateName); + if (fDisplayName == NULL) + return B_NO_MEMORY; + + char* remainder = fDisplayName; + while (char* underscore = strchr(remainder, '_')) { + *underscore = ' '; + remainder = underscore + 1; + } + } + + return B_OK; +} + + +void +PackageVolumeState::Unset() +{ + free(fName); + fName = NULL; + + free(fDisplayName); + fDisplayName = NULL; + + free(fSystemPackage); + fSystemPackage = NULL; +} + + +const char* +PackageVolumeState::DisplayName() const +{ + return fDisplayName != NULL ? fDisplayName : "Latest version"; +} + + +status_t +PackageVolumeState::SetSystemPackage(const char* package) +{ + if (fSystemPackage != NULL) + free(fSystemPackage); + + fSystemPackage = strdup(package); + return fSystemPackage != NULL ? B_OK : B_NO_MEMORY; +} + + +void +PackageVolumeState::GetPackagePath(const char* name, char* path, + size_t pathSize) +{ + if (fName == NULL) { + // the current state -- packages are directly in the packages directory + strlcpy(path, name, pathSize); + } else { + // an old state + snprintf(path, pathSize, "%s/%s/%s", kAdministrativeDirectory, fName, + name); + } +} + + +/*static*/ bool +PackageVolumeState::IsNewer(const PackageVolumeState* a, + const PackageVolumeState* b) +{ + if (b->fName == NULL) + return false; + if (a->fName == NULL) + return true; + return strcmp(a->fName, b->fName) > 0; +} + + +// #pragma mark - PackageVolumeInfo + + +PackageVolumeInfo::PackageVolumeInfo() + : + BReferenceable(), + fStates() +{ +} + + +PackageVolumeInfo::~PackageVolumeInfo() +{ + while (PackageVolumeState* state = fStates.RemoveHead()) + delete state; +} + + +status_t +PackageVolumeInfo::SetTo(Directory* baseDirectory, const char* packagesPath) +{ + TRACE("PackageVolumeInfo::SetTo()\n"); + + // get the packages directory + DIR* dir = open_directory(baseDirectory, packagesPath); + if (dir == NULL) { + TRACE("PackageVolumeInfo::SetTo(): failed to open packages directory: " + "%s\n", strerror(errno)); + return errno; + } + CObjectDeleter dirCloser(dir, &closedir); + + Directory* packagesDirectory = directory_from(dir); + packagesDirectory->Acquire(); + + // add the current state + PackageVolumeState* state = _AddState(NULL); + if (state == NULL) + return B_NO_MEMORY; + status_t error = _InitState(packagesDirectory, dir, state); + if (error != B_OK) { + TRACE("PackageVolumeInfo::SetTo(): failed to init current state: " + "%s\n", strerror(error)); + return error; + } + + // Iterate through the packages/administrative directory to find old state + // directories. + if (DIR* administrativeDir = open_directory(packagesDirectory, + kAdministrativeDirectory)) { + while (dirent* entry = readdir(administrativeDir)) { + if (strncmp(entry->d_name, "state_", 6) == 0) { + TRACE(" old state directory \"%s\"\n", entry->d_name); + _AddState(entry->d_name); + } + } + + closedir(administrativeDir); + + fStates.Sort(&PackageVolumeState::IsNewer); + + // initialize the old states + for (state = fStates.GetNext(state); state != NULL;) { + PackageVolumeState* nextState = fStates.GetNext(state); + if (state->Name()) { + error = _InitState(packagesDirectory, dir, state); + if (error != B_OK) { + TRACE("PackageVolumeInfo::SetTo(): failed to init state " + "\"%s\": %s\n", state->Name(), strerror(error)); + fStates.Remove(state); + delete state; + } + } + state = nextState; + } + } else { + TRACE("PackageVolumeInfo::SetTo(): failed to open administrative " + "directory: %s\n", strerror(errno)); + } + + return B_OK; +} + + +PackageVolumeState* +PackageVolumeInfo::_AddState(const char* stateName) +{ + PackageVolumeState* state = new(std::nothrow) PackageVolumeState; + if (state == NULL) + return NULL; + + if (state->SetTo(stateName) != B_OK) { + delete state; + return NULL; + } + + fStates.Add(state); + return state; +} + + +status_t +PackageVolumeInfo::_InitState(Directory* packagesDirectory, DIR* dir, + PackageVolumeState* state) +{ + // find the system package + char systemPackageName[B_FILE_NAME_LENGTH]; + status_t error = _ParseActivatedPackagesFile(packagesDirectory, state, + systemPackageName, sizeof(systemPackageName)); + if (error == B_OK) { + // check, if package exists + for (PackageVolumeState* otherState = state; otherState != NULL; + otherState = fStates.GetPrevious(otherState)) { + char packagePath[B_PATH_NAME_LENGTH]; + otherState->GetPackagePath(systemPackageName, packagePath, + sizeof(packagePath)); + struct stat st; + if (get_stat(packagesDirectory, packagePath, st) == B_OK + && S_ISREG(st.st_mode)) { + state->SetSystemPackage(packagePath); + break; + } + } + } else { + TRACE("PackageVolumeInfo::_InitState(): failed to parse " + "activated-packages: %s\n", strerror(error)); + + // No or invalid activated-packages file. That is OK for the current + // state. We'll iterate through the packages directory to find the + // system package. We don't do that for old states, though. + if (state->Name() != NULL) + return B_ENTRY_NOT_FOUND; + + while (dirent* entry = readdir(dir)) { + // The name must end with ".hpkg". + if (is_system_package(entry->d_name)) { + state->SetSystemPackage(entry->d_name); + break; + } + } + } + + if (state->SystemPackage() == NULL) + return B_ENTRY_NOT_FOUND; + + return B_OK; +} + + +status_t +PackageVolumeInfo::_ParseActivatedPackagesFile(Directory* packagesDirectory, + PackageVolumeState* state, char* packageName, size_t packageNameSize) +{ + // open the activated-packages file + char path[3 * B_FILE_NAME_LENGTH + 2]; + snprintf(path, sizeof(path), "%s/%s/%s", + kAdministrativeDirectory, state->Name() != NULL ? state->Name() : "", + kActivatedPackagesFile); + int fd = open_from(packagesDirectory, path, O_RDONLY); + if (fd < 0) + return fd; + FileDescriptorCloser fdCloser(fd); + + struct stat st; + if (fstat(fd, &st) != 0) + return errno; + if (!S_ISREG(st.st_mode)) + return B_ENTRY_NOT_FOUND; + + // read the file until we find the system package line + size_t remainingBytes = 0; + for (;;) { + ssize_t bytesRead = read(fd, path + remainingBytes, + sizeof(path) - remainingBytes - 1); + if (bytesRead <= 0) + return B_ENTRY_NOT_FOUND; + + remainingBytes += bytesRead; + path[remainingBytes] = '\0'; + + char* line = path; + while (char* lineEnd = strchr(line, '\n')) { + *lineEnd = '\0'; + if (is_system_package(line)) { + return strlcpy(packageName, line, packageNameSize) + < packageNameSize + ? B_OK : B_NAME_TOO_LONG; + } + + line = lineEnd + 1; + } + + // move the remainder to the start of the buffer + if (line < path + remainingBytes) { + size_t left = path + remainingBytes - line; + memmove(path, line, left); + remainingBytes = left; + } else + remainingBytes = 0; + } + + return B_ENTRY_NOT_FOUND; +} diff --git a/src/system/boot/loader/package_support.h b/src/system/boot/loader/package_support.h new file mode 100644 index 0000000000..3c38ede776 --- /dev/null +++ b/src/system/boot/loader/package_support.h @@ -0,0 +1,77 @@ +/* + * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_SUPPORT_H +#define PACKAGE_SUPPORT_H + + +#include + +#include +#include + + +class Directory; + + +class PackageVolumeState : public DoublyLinkedListLinkImpl { +public: + PackageVolumeState(); + ~PackageVolumeState(); + + status_t SetTo(const char* stateName); + void Unset(); + + const char* Name() const + { return fName; } + const char* DisplayName() const; + + const char* SystemPackage() const + { return fSystemPackage; } + status_t SetSystemPackage(const char* package); + + void GetPackagePath(const char* name, char* path, + size_t pathSize); + + static bool IsNewer(const PackageVolumeState* a, + const PackageVolumeState* b); + +private: + char* fName; + char* fDisplayName; + char* fSystemPackage; +}; + +typedef DoublyLinkedList PackageVolumeStateList; + + +class PackageVolumeInfo : public BReferenceable { +public: + typedef PackageVolumeStateList StateList; + +public: + PackageVolumeInfo(); + ~PackageVolumeInfo(); + + status_t SetTo(Directory* baseDirectory, + const char* packagesPath); + + const StateList& States() const + { return fStates; } + +private: + PackageVolumeState* _AddState(const char* stateName); + status_t _InitState(Directory* packagesDirectory, + DIR* dir, PackageVolumeState* state); + status_t _ParseActivatedPackagesFile( + Directory* packagesDirectory, + PackageVolumeState* state, + char* packageName, size_t packageNameSize); + +private: + StateList fStates; +}; + + +#endif // PACKAGE_SUPPORT_H diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 43ee2e7018..02e5d609e6 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -23,6 +23,7 @@ #include #include +#include "package_support.h" #include "RootFileSystem.h" #include "file_systems/packagefs/packagefs.h" @@ -418,7 +419,8 @@ BootVolume::BootVolume() : fRootDirectory(NULL), fSystemDirectory(NULL), - fPackaged(false) + fPackageVolumeInfo(NULL), + fPackageVolumeState(NULL) { } @@ -430,7 +432,46 @@ BootVolume::~BootVolume() status_t -BootVolume::SetTo(Directory* rootDirectory) +BootVolume::SetTo(Directory* rootDirectory, + PackageVolumeInfo* packageVolumeInfo, + PackageVolumeState* packageVolumeState) +{ + Unset(); + + status_t error = _SetTo(rootDirectory, packageVolumeInfo, + packageVolumeState); + if (error != B_OK) + Unset(); + + return error; +} + + +void +BootVolume::Unset() +{ + if (fRootDirectory != NULL) { + fRootDirectory->Release(); + fRootDirectory = NULL; + } + + if (fSystemDirectory != NULL) { + fSystemDirectory->Release(); + fSystemDirectory = NULL; + } + + if (fPackageVolumeInfo != NULL) { + fPackageVolumeInfo->ReleaseReference(); + fPackageVolumeInfo = NULL; + fPackageVolumeState = NULL; + } +} + + +status_t +BootVolume::_SetTo(Directory* rootDirectory, + PackageVolumeInfo* packageVolumeInfo, + PackageVolumeState* packageVolumeState) { Unset(); @@ -451,13 +492,32 @@ BootVolume::SetTo(Directory* rootDirectory) fSystemDirectory = static_cast(systemNode); + if (packageVolumeInfo == NULL) { + // get a package volume info + BReference packageVolumeInfoReference( + new(std::nothrow) PackageVolumeInfo); + status_t error = packageVolumeInfoReference->SetTo(fSystemDirectory, + "packages"); + if (error != B_OK) { + // apparently not packaged + return B_OK; + } + + fPackageVolumeInfo = packageVolumeInfoReference.Detach(); + } else { + fPackageVolumeInfo = packageVolumeInfo; + fPackageVolumeInfo->AcquireReference(); + } + + fPackageVolumeState = packageVolumeState != NULL + ? packageVolumeState : fPackageVolumeInfo->States().Head(); + // try opening the system package int packageFD = _OpenSystemPackage(); - fPackaged = packageFD >= 0; - if (!fPackaged) - return B_OK; + if (packageFD < 0) + return packageFD; - // the system is packaged -- mount the packagefs + // mount packagefs Directory* packageRootDirectory; status_t error = packagefs_mount_file(packageFD, fSystemDirectory, packageRootDirectory); @@ -474,23 +534,6 @@ BootVolume::SetTo(Directory* rootDirectory) } -void -BootVolume::Unset() -{ - if (fRootDirectory != NULL) { - fRootDirectory->Release(); - fRootDirectory = NULL; - } - - if (fSystemDirectory != NULL) { - fSystemDirectory->Release(); - fSystemDirectory = NULL; - } - - fPackaged = false; -} - - int BootVolume::_OpenSystemPackage() { @@ -505,29 +548,9 @@ BootVolume::_OpenSystemPackage() return -1; Directory* packageDirectory = (Directory*)packagesNode; - // search for the system package - int fd = -1; - void* cookie; - if (packageDirectory->Open(&cookie, O_RDONLY) == B_OK) { - char name[B_FILE_NAME_LENGTH]; - while (packageDirectory->GetNextEntry(cookie, name, sizeof(name)) - == B_OK) { - // The name must end with ".hpkg". - size_t nameLength = strlen(name); - if (nameLength < 6 || strcmp(name + nameLength - 5, ".hpkg") != 0) - continue; - - // The name must either be "haiku.hpkg" or start with "haiku-". - if (strcmp(name, "haiku.hpkg") == 0 - || strncmp(name, "haiku-", 6) == 0) { - fd = open_from(packageDirectory, name, O_RDONLY); - break; - } - } - packageDirectory->Close(cookie); - } - - return fd; + // open the system package + return open_from(packageDirectory, fPackageVolumeState->SystemPackage(), + O_RDONLY); } @@ -561,8 +584,13 @@ register_boot_file_system(BootVolume& bootVolume) gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET, partition->offset); - if (bootVolume.IsPackaged()) + + if (bootVolume.IsPackaged()) { gBootVolume.SetBool(BOOT_VOLUME_PACKAGED, true); + PackageVolumeState* state = bootVolume.GetPackageVolumeState(); + if (state->Name() != NULL) + gBootVolume.AddString(BOOT_VOLUME_PACKAGES_STATE, state->Name()); + } Node *device = get_node_from(partition->FD()); if (device == NULL) {