[haiku-commits] haiku: hrev46378 - src/system/libroot/os src/bin src/system/runtime_loader headers/private/system src/kits/storage

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 17 Nov 2013 02:26:47 +0100 (CET)

hrev46378 adds 6 changesets to branch 'master'
old head: 905f910e5364ca9b0e0ca98fe9e35fa6cffe42ed
new head: 4f5e93857671d231372096457d024926635dcee6
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=4f5e938+%5E905f910

----------------------------------------------------------------------------

b83f9b3: HAIKU_DEFINES: Add __HAIKU_PRIMARY_PACKAGING_ARCH
  
  * It is set to the primary architecture we're building for.
  * Remove __HAIKU__. The macro is already defined by the compiler.

cf7e2ad: runtime loader: Export get_executable_architecture() function
  
  Given a path of an ELF file, it tries to determine its architecture.

60b39cd: Add get_*architecture() API, extend find_path*() API
  
  * Add get_architecture(), get_primary_architecture(),
    get_secondary_architectures(), guess_architecture_for_path() to get
    the caller's architecture, the primary architecture, all secondary
    architectures, or the architecture associated with a specified path
    respectively.
  * Rename the find_path*() functions to find_path*_etc() and add an
    optional architecture parameter. Add simplified find_path*()
    functions.
  * BPathFinder: Add FindPath[s]() versions with an architecture
    parameter.

2c2f3ab: findpaths: Add an -a <architecture> option

c39c928: Add get_architectures() and C++ versions
  
  * get_architectures() returns the primary and the secondary
    architectures in one array. That turned out to be convenient.
  * Add C++ versions for get[_secondary]_architectures(), returning a
    BStringList.

4f5e938: Add setarch and getarch commands

                                    [ Ingo Weinhold <ingo_weinhold@xxxxxx> ]

----------------------------------------------------------------------------

22 files changed, 1285 insertions(+), 71 deletions(-)
build/jam/BuildSetup                             |   4 +-
build/jam/images/HaikuImage                      |   8 +-
build/jam/images/HaikuImageBootstrap             |   4 +-
headers/os/storage/FindDirectory.h               |  24 +-
headers/os/storage/PathFinder.h                  |   8 +
headers/os/support/Architecture.h                |  42 +++
headers/private/runtime_loader/runtime_loader.h  |   2 +
headers/private/system/architecture_private.h    |  26 ++
headers/private/system/find_directory_private.h  |  29 +-
src/bin/Jamfile                                  |   2 +
src/bin/findpaths.cpp                            |  20 +-
src/bin/getarch.cpp                              | 169 ++++++++++
src/bin/setarch.cpp                              | 230 ++++++++++++++
src/kits/storage/PathFinder.cpp                  |  46 ++-
src/kits/support/Architecture.cpp                |  53 ++++
src/kits/support/Jamfile                         |   1 +
src/system/libroot/os/Architecture.cpp           | 129 ++++++++
src/system/libroot/os/Jamfile                    |   1 +
src/system/libroot/os/find_paths.cpp             | 315 +++++++++++++++++--
src/system/runtime_loader/export.cpp             |   1 +
src/system/runtime_loader/runtime_loader.cpp     | 240 +++++++++++++-
.../runtime_loader/runtime_loader_private.h      |   2 +

############################################################################

Commit:      b83f9b39401caf09c46d66487c3c2174e0742598
URL:         http://cgit.haiku-os.org/haiku/commit/?id=b83f9b3
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sat Nov 16 21:18:40 2013 UTC

HAIKU_DEFINES: Add __HAIKU_PRIMARY_PACKAGING_ARCH

* It is set to the primary architecture we're building for.
* Remove __HAIKU__. The macro is already defined by the compiler.

----------------------------------------------------------------------------

diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup
index ed49622..858fb07 100644
--- a/build/jam/BuildSetup
+++ b/build/jam/BuildSetup
@@ -125,7 +125,9 @@ if $(HAIKU_PACKAGING_ARCH) {
        KernelArchitectureSetup $(HAIKU_PACKAGING_ARCH) ;
 }
 
-HAIKU_DEFINES = __HAIKU__ ;
+# define primary packaging architecture macro
+HAIKU_DEFINES = __HAIKU_PRIMARY_PACKAGING_ARCH=\\\"$(HAIKU_PACKAGING_ARCH)\\\" 
;
+
 HAIKU_LIBSUPC++ = $(HAIKU_LIBSUPC++_$(HAIKU_PACKAGING_ARCH)) ;
 HAIKU_LIBSTDC++ = $(HAIKU_LIBSTDC++_$(HAIKU_PACKAGING_ARCH)) ;
 

############################################################################

Commit:      cf7e2ad8129137fa3a25d8831c363ead09e99b2b
URL:         http://cgit.haiku-os.org/haiku/commit/?id=cf7e2ad
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sat Nov 16 21:20:51 2013 UTC

runtime loader: Export get_executable_architecture() function

Given a path of an ELF file, it tries to determine its architecture.

----------------------------------------------------------------------------

diff --git a/headers/private/runtime_loader/runtime_loader.h 
b/headers/private/runtime_loader/runtime_loader.h
index 4d32841..3772a09 100644
--- a/headers/private/runtime_loader/runtime_loader.h
+++ b/headers/private/runtime_loader/runtime_loader.h
@@ -41,6 +41,8 @@ struct rld_export {
                image_id* _imageID,     char** _imagePath, char** _symbolName,
                int32* _type, void** _location);
        status_t (*test_executable)(const char *path, char *interpreter);
+       status_t (*get_executable_architecture)(const char *path,
+               const char** _architecture);
        status_t (*get_next_image_dependency)(image_id id, uint32 *cookie,
                const char **_name);
 
diff --git a/src/system/runtime_loader/export.cpp 
b/src/system/runtime_loader/export.cpp
index f8c0b06..bae3006 100644
--- a/src/system/runtime_loader/export.cpp
+++ b/src/system/runtime_loader/export.cpp
@@ -53,6 +53,7 @@ struct rld_export gRuntimeLoader = {
        get_nth_symbol,
        get_nearest_symbol_at_address,
        test_executable,
+       get_executable_architecture,
        get_next_image_dependency,
 
        elf_reinit_after_fork,
diff --git a/src/system/runtime_loader/runtime_loader.cpp 
b/src/system/runtime_loader/runtime_loader.cpp
index 392deac..2b2251b 100644
--- a/src/system/runtime_loader/runtime_loader.cpp
+++ b/src/system/runtime_loader/runtime_loader.cpp
@@ -9,17 +9,22 @@
 
 #include "runtime_loader_private.h"
 
-#include <syscalls.h>
-#include <user_runtime.h>
-
-#include <directories.h>
-
 #include <string.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 
 #include <algorithm>
 
+#include <ByteOrder.h>
+
+#include <directories.h>
+#include <image_defs.h>
+#include <syscalls.h>
+#include <user_runtime.h>
+#include <vm_defs.h>
+
+#include "elf_symbol_lookup.h"
+
 
 struct user_space_program_args *gProgramArgs;
 void *__gCommPageAddress;
@@ -385,6 +390,231 @@ out:
 }
 
 
+static bool
+determine_x86_abi(int fd, const Elf32_Ehdr& elfHeader, bool& _isGcc2)
+{
+       // Unless we're a little-endian CPU, don't bother. We're not x86, so it
+       // doesn't matter all that much whether we can determine the correct gcc
+       // ABI. This saves the code below from having to deal with endianess
+       // conversion.
+#if B_HOST_IS_LENDIAN
+
+       // Since we don't want to load the complete image, we can't use the
+       // functions that normally determine the Haiku version and ABI. Instead
+       // we'll load the symbol and string tables and resolve the ABI symbol
+       // manually.
+
+       // map the file into memory
+       struct stat st;
+       if (_kern_read_stat(fd, NULL, true, &st, sizeof(st)) != B_OK)
+               return false;
+
+       void* fileBaseAddress;
+       area_id area = _kern_map_file("mapped file", &fileBaseAddress,
+               B_ANY_ADDRESS, st.st_size, B_READ_AREA, REGION_NO_PRIVATE_MAP, 
false,
+               fd, 0);
+       if (area < 0)
+               return false;
+
+       struct AreaDeleter {
+               AreaDeleter(area_id area)
+                       :
+                       fArea(area)
+               {
+               }
+
+               ~AreaDeleter()
+               {
+                       _kern_delete_area(fArea);
+               }
+
+       private:
+               area_id fArea;
+       } areaDeleter(area);
+
+       // get the section headers
+       if (elfHeader.e_shoff == 0 || elfHeader.e_shentsize < 
sizeof(Elf32_Shdr))
+               return false;
+
+       size_t sectionHeadersSize = elfHeader.e_shentsize * elfHeader.e_shnum;
+       if (elfHeader.e_shoff + (off_t)sectionHeadersSize > st.st_size)
+               return false;
+
+       void* sectionHeaders = (uint8*)fileBaseAddress + elfHeader.e_shoff;
+
+       // find the sections we need
+       uint32* symbolHash = NULL;
+       uint32 symbolHashSize = 0;
+       uint32 symbolHashChainSize = 0;
+       Elf32_Sym* symbolTable = NULL;
+       uint32 symbolTableSize = 0;
+       const char* stringTable = NULL;
+       off_t stringTableSize = 0;
+
+       for (int32 i = 0; i < elfHeader.e_shnum; i++) {
+               Elf32_Shdr* sectionHeader
+                       = (Elf32_Shdr*)((uint8*)sectionHeaders + i * 
elfHeader.e_shentsize);
+               if ((off_t)sectionHeader->sh_offset + 
(off_t)sectionHeader->sh_size
+                               > st.st_size) {
+                       continue;
+               }
+
+               void* sectionAddress = (uint8*)fileBaseAddress
+                       + sectionHeader->sh_offset;
+
+               switch (sectionHeader->sh_type) {
+                       case SHT_HASH:
+                               symbolHash = (uint32*)sectionAddress;
+                               if (sectionHeader->sh_size < 
(off_t)sizeof(symbolHash[0]))
+                                       return false;
+                               symbolHashSize = symbolHash[0];
+                               symbolHashChainSize
+                                       = sectionHeader->sh_size / 
sizeof(symbolHash[0]);
+                               if (symbolHashChainSize < symbolHashSize + 2)
+                                       return false;
+                               symbolHashChainSize -= symbolHashSize + 2;
+                               break;
+                       case SHT_DYNSYM:
+                               symbolTable = (Elf32_Sym*)sectionAddress;
+                               symbolTableSize = sectionHeader->sh_size;
+                               break;
+                       case SHT_STRTAB:
+                               // .shstrtab has the same type as .dynstr, but 
it isn't loaded
+                               // into memory.
+                               if (sectionHeader->sh_addr == 0)
+                                       continue;
+                               stringTable = (const char*)sectionAddress;
+                               stringTableSize = (off_t)sectionHeader->sh_size;
+                               break;
+                       default:
+                               continue;
+               }
+       }
+
+       if (symbolHash == NULL || symbolTable == NULL || stringTable == NULL)
+               return false;
+       uint32 symbolCount
+               = std::min(symbolTableSize / sizeof(Elf32_Sym), 
symbolHashChainSize);
+       if (symbolCount < symbolHashSize)
+               return false;
+
+       // look up the ABI symbol
+       const char* name = B_SHARED_OBJECT_HAIKU_ABI_VARIABLE_NAME;
+       size_t nameLength = strlen(name);
+       uint32 bucket = elf_hash(name) % symbolHashSize;
+
+       for (uint32 i = symbolHash[bucket + 2]; i < symbolCount && i != 
STN_UNDEF;
+               i = symbolHash[2 + symbolHashSize + i]) {
+               Elf32_Sym* symbol = symbolTable + i;
+               if (symbol->st_shndx != SHN_UNDEF
+                       && ((symbol->Bind() == STB_GLOBAL) || (symbol->Bind() 
== STB_WEAK))
+                       && symbol->Type() == STT_OBJECT
+                       && (off_t)symbol->st_name + (off_t)nameLength < 
stringTableSize
+                       && strcmp(stringTable + symbol->st_name, name) == 0) {
+                       if (symbol->st_value > 0 && symbol->st_size >= 
sizeof(uint32)
+                               && symbol->st_shndx < elfHeader.e_shnum) {
+                               Elf32_Shdr* sectionHeader = 
(Elf32_Shdr*)((uint8*)sectionHeaders
+                                       + symbol->st_shndx * 
elfHeader.e_shentsize);
+                               if (symbol->st_value >= sectionHeader->sh_addr
+                                       && symbol->st_value
+                                               <= sectionHeader->sh_addr + 
sectionHeader->sh_size) {
+                                       off_t fileOffset = symbol->st_value - 
sectionHeader->sh_addr
+                                               + sectionHeader->sh_offset;
+                                       if (fileOffset + sizeof(uint32) <= 
st.st_size) {
+                                               uint32 abi
+                                                       = 
*(uint32*)((uint8*)fileBaseAddress + fileOffset);
+                                               _isGcc2 = (abi & 
B_HAIKU_ABI_MAJOR)
+                                                       == B_HAIKU_ABI_GCC_2;
+                                               return true;
+                                       }
+                               }
+                       }
+
+                       return false;
+               }
+       }
+
+       // ABI symbol not found. That means the object pre-dates its 
introduction
+       // in Haiku. So this is most likely gcc 2. We don't fall back to reading
+       // the comment sections to verify.
+       _isGcc2 = true;
+       return true;
+#else  // not little endian
+       return false;
+#endif
+}
+
+
+static status_t
+get_executable_architecture(int fd, const char** _architecture)
+{
+       // Read the ELF header. We read the 32 bit header. Generally the 
e_machine
+       // field is the last one that interests us and the 64 bit header is 
still
+       // identical at that point.
+       Elf32_Ehdr elfHeader;
+       ssize_t bytesRead = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader));
+       if (bytesRead < 0)
+               return bytesRead;
+       if ((size_t)bytesRead != sizeof(elfHeader))
+               return B_NOT_AN_EXECUTABLE;
+
+       // check whether this is indeed an ELF file
+       if (memcmp(elfHeader.e_ident, ELF_MAGIC, 4) != 0)
+               return B_NOT_AN_EXECUTABLE;
+
+       // check the architecture
+       uint16 machine = elfHeader.e_machine;
+       if ((elfHeader.e_ident[EI_DATA] == ELFDATA2LSB) != (B_HOST_IS_LENDIAN 
!= 0))
+               machine = (machine >> 8) | (machine << 8);
+
+       const char* architecture = NULL;
+       switch (machine) {
+               case EM_386:
+               case EM_486:
+               {
+                       bool isGcc2;
+                       if (determine_x86_abi(fd, elfHeader, isGcc2) && isGcc2)
+                               architecture = "x86_gcc2";
+                       else
+                               architecture = "x86";
+                       break;
+               }
+               case EM_68K:
+                       architecture = "m68k";
+                       break;
+               case EM_PPC:
+                       architecture = "ppc";
+                       break;
+               case EM_ARM:
+                       architecture = "arm";
+                       break;
+               case EM_X86_64:
+                       architecture = "x86_64";
+                       break;
+       }
+
+       if (architecture == NULL)
+               return B_NOT_SUPPORTED;
+
+       *_architecture = architecture;
+       return B_OK;
+}
+
+
+status_t
+get_executable_architecture(const char* path, const char** _architecture)
+{
+       int fd = _kern_open(-1, path, O_RDONLY, 0);
+       if (fd < 0)
+               return fd;
+
+       status_t error = get_executable_architecture(fd, _architecture);
+
+       _kern_close(fd);
+       return error;
+}
+
+
 /*!
        This is the main entry point of the runtime loader as
        specified by its ld-script.
diff --git a/src/system/runtime_loader/runtime_loader_private.h 
b/src/system/runtime_loader/runtime_loader_private.h
index 4a0faa3..81dabfe 100644
--- a/src/system/runtime_loader/runtime_loader_private.h
+++ b/src/system/runtime_loader/runtime_loader_private.h
@@ -58,6 +58,8 @@ int runtime_loader(void* arg, void* commpage);
 int open_executable(char* name, image_type type, const char* rpath,
        const char* programPath, const char* abiSpecificSubDir);
 status_t test_executable(const char* path, char* interpreter);
+status_t get_executable_architecture(const char* path,
+       const char** _architecture);
 
 void terminate_program(void);
 image_id load_program(char const* path, void** entry);

############################################################################

Commit:      60b39cd7416028e61e3d30bb3ba28bd3526e6001
URL:         http://cgit.haiku-os.org/haiku/commit/?id=60b39cd
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sat Nov 16 21:27:47 2013 UTC

Add get_*architecture() API, extend find_path*() API

* Add get_architecture(), get_primary_architecture(),
  get_secondary_architectures(), guess_architecture_for_path() to get
  the caller's architecture, the primary architecture, all secondary
  architectures, or the architecture associated with a specified path
  respectively.
* Rename the find_path*() functions to find_path*_etc() and add an
  optional architecture parameter. Add simplified find_path*()
  functions.
* BPathFinder: Add FindPath[s]() versions with an architecture
  parameter.

----------------------------------------------------------------------------

diff --git a/headers/os/storage/FindDirectory.h 
b/headers/os/storage/FindDirectory.h
index 761a1ee..5b2fba3 100644
--- a/headers/os/storage/FindDirectory.h
+++ b/headers/os/storage/FindDirectory.h
@@ -170,16 +170,26 @@ extern "C" {
 status_t find_directory(directory_which which, dev_t volume, bool createIt,
        char* pathString, int32 length);
 
-status_t find_path(const void* codePointer, const char* dependency,
-       path_base_directory baseDirectory, const char* subPath, uint32 flags,
-       char* pathBuffer, size_t bufferSize);
+status_t find_path(const void* codePointer, path_base_directory baseDirectory,
+       const char* subPath, char* pathBuffer, size_t bufferSize);
 
-status_t find_path_for_path(const char* path, const char* dependency,
-       path_base_directory baseDirectory, const char* subPath, uint32 flags,
-       char* pathBuffer, size_t bufferSize);
+status_t find_path_etc(const void* codePointer, const char* dependency,
+       const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize);
+
+status_t find_path_for_path(const char* path, path_base_directory 
baseDirectory,
+       const char* subPath, char* pathBuffer, size_t bufferSize);
+
+status_t find_path_for_path_etc(const char* path, const char* dependency,
+       const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize);
 
 status_t find_paths(path_base_directory baseDirectory, const char* subPath,
-       uint32 flags, char*** _paths, size_t* _pathCount);
+       char*** _paths, size_t* _pathCount);
+
+status_t find_paths_etc(const char* architecture,
+       path_base_directory baseDirectory, const char* subPath, uint32 flags,
+       char*** _paths, size_t* _pathCount);
 
 
 #ifdef __cplusplus
diff --git a/headers/os/storage/PathFinder.h b/headers/os/storage/PathFinder.h
index a1819fb..80f342a 100644
--- a/headers/os/storage/PathFinder.h
+++ b/headers/os/storage/PathFinder.h
@@ -31,6 +31,10 @@ public:
                        status_t                        SetTo(const entry_ref& 
ref,
                                                                        const 
char* dependency = NULL);
 
+                       status_t                        FindPath(const char* 
architecture,
+                                                                       
path_base_directory baseDirectory,
+                                                                       const 
char* subPath, uint32 flags,
+                                                                       BPath& 
path);
                        status_t                        
FindPath(path_base_directory baseDirectory,
                                                                        const 
char* subPath, uint32 flags,
                                                                        BPath& 
path);
@@ -39,6 +43,10 @@ public:
                        status_t                        
FindPath(path_base_directory baseDirectory,
                                                                        BPath& 
path);
 
+       static  status_t                        FindPaths(const char* 
architecture,
+                                                                       
path_base_directory baseDirectory,
+                                                                       const 
char* subPath, uint32 flags,
+                                                                       
BStringList& paths);
        static  status_t                        FindPaths(path_base_directory 
baseDirectory,
                                                                        const 
char* subPath, uint32 flags,
                                                                        
BStringList& paths);
diff --git a/headers/os/support/Architecture.h 
b/headers/os/support/Architecture.h
new file mode 100644
index 0000000..7781397
--- /dev/null
+++ b/headers/os/support/Architecture.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _SUPPORT_ARCHITECTURE_H
+#define _SUPPORT_ARCHITECTURE_H
+
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+
+
+__BEGIN_DECLS
+
+
+const char*    get_architecture();
+const char*    get_primary_architecture();
+size_t         get_secondary_architectures(const char** architectures,
+                               size_t count);
+const char*    guess_architecture_for_path(const char* path);
+
+
+__END_DECLS
+
+
+#endif /* _SUPPORT_ARCHITECTURE_H */
diff --git a/headers/private/system/architecture_private.h 
b/headers/private/system/architecture_private.h
new file mode 100644
index 0000000..e638375
--- /dev/null
+++ b/headers/private/system/architecture_private.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _SYSTEM_ARCHITECTURE_PRIVATE_H
+#define _SYSTEM_ARCHITECTURE_PRIVATE_H
+
+
+#include <Architecture.h>
+
+
+__BEGIN_DECLS
+
+
+const char*    __get_architecture();
+const char*    __get_primary_architecture();
+size_t         __get_secondary_architectures(const char** architectures,
+                               size_t count);
+const char*    __guess_architecture_for_path(const char* path);
+
+
+__END_DECLS
+
+
+#endif /* _SYSTEM_ARCHITECTURE_PRIVATE_H */
diff --git a/headers/private/system/find_directory_private.h 
b/headers/private/system/find_directory_private.h
index 3bdd7bf..5db48f3 100644
--- a/headers/private/system/find_directory_private.h
+++ b/headers/private/system/find_directory_private.h
@@ -17,16 +17,31 @@ __BEGIN_DECLS
 status_t __find_directory(directory_which which, dev_t device, bool createIt,
        char *returnedPath, int32 pathLength);
 
-status_t __find_path(const void* codePointer, const char* dependency,
-       path_base_directory baseDirectory, const char* subPath, uint32 flags,
-       char* pathBuffer, size_t bufferSize);
+status_t __find_path(const void* codePointer, path_base_directory 
baseDirectory,
+       const char* subPath, char* pathBuffer, size_t bufferSize);
 
-status_t __find_path_for_path(const char* path, const char* dependency,
-       path_base_directory baseDirectory, const char* subPath, uint32 flags,
-       char* pathBuffer, size_t bufferSize);
+status_t __find_path_etc(const void* codePointer, const char* dependency,
+       const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize);
+
+status_t __find_path_for_path(const char* path,
+       path_base_directory baseDirectory, const char* subPath, char* 
pathBuffer,
+       size_t bufferSize);
+
+status_t __find_path_for_path_etc(const char* path, const char* dependency,
+       const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize);
 
 status_t __find_paths(path_base_directory baseDirectory, const char* subPath,
-       uint32 flags, char*** _paths, size_t* _pathCount);
+       char*** _paths, size_t* _pathCount);
+
+status_t __find_paths_etc(const char* architecture,
+       path_base_directory baseDirectory, const char* subPath, uint32 flags,
+       char*** _paths, size_t* _pathCount);
+
+const char* __guess_secondary_architecture_from_path(const char* path,
+       const char* const* secondaryArchitectures,
+       size_t secondaryArchitectureCount);
 
 
 __END_DECLS
diff --git a/src/kits/storage/PathFinder.cpp b/src/kits/storage/PathFinder.cpp
index 5794189..f51eb65 100644
--- a/src/kits/storage/PathFinder.cpp
+++ b/src/kits/storage/PathFinder.cpp
@@ -55,9 +55,11 @@ BPathFinder::SetTo(const entry_ref& ref, const char* 
dependency)
 }
 
 
+
 status_t
-BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath,
-       uint32 flags, BPath& path)
+BPathFinder::FindPath(const char* architecture,
+       path_base_directory baseDirectory, const char* subPath, uint32 flags,
+       BPath& path)
 {
        path.Unset();
 
@@ -71,11 +73,11 @@ BPathFinder::FindPath(path_base_directory baseDirectory, 
const char* subPath,
        status_t error;
 
        if (!fPath.IsEmpty()) {
-               error = find_path_for_path(fPath, dependency, baseDirectory, 
subPath,
-                       flags, pathBuffer, sizeof(pathBuffer));
+               error = find_path_for_path_etc(fPath, dependency, architecture,
+                       baseDirectory, subPath, flags, pathBuffer, 
sizeof(pathBuffer));
        } else {
-               error = find_path(fCodePointer, dependency, baseDirectory, 
subPath,
-                       flags, pathBuffer, sizeof(pathBuffer));
+               error = find_path_etc(fCodePointer, dependency, architecture,
+                       baseDirectory, subPath, flags, pathBuffer, 
sizeof(pathBuffer));
        }
 
        if (error != B_OK)
@@ -84,33 +86,41 @@ BPathFinder::FindPath(path_base_directory baseDirectory, 
const char* subPath,
        return path.SetTo(pathBuffer);
 }
 
+status_t
+BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath,
+       uint32 flags, BPath& path)
+{
+       return FindPath(NULL, baseDirectory, subPath, flags, path);
+}
+
 
 status_t
 BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath,
        BPath& path)
 {
-       return FindPath(baseDirectory, subPath, 0, path);
+       return FindPath(NULL, baseDirectory, subPath, 0, path);
 }
 
 
 status_t
 BPathFinder::FindPath(path_base_directory baseDirectory, BPath& path)
 {
-       return FindPath(baseDirectory, NULL, 0, path);
+       return FindPath(NULL, baseDirectory, NULL, 0, path);
 }
 
 
 /*static*/ status_t
-BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath,
-       uint32 flags, BStringList& paths)
+BPathFinder::FindPaths(const char* architecture,
+       path_base_directory baseDirectory, const char* subPath, uint32 flags,
+       BStringList& paths)
 {
        paths.MakeEmpty();
 
        // get the paths
        char** pathArray;
        size_t pathCount;
-       status_t error = find_paths(baseDirectory, subPath, flags, &pathArray,
-               &pathCount);
+       status_t error = find_paths_etc(architecture, baseDirectory, subPath, 
flags,
+               &pathArray, &pathCount);
        if (error != B_OK)
                return error;
 
@@ -129,16 +139,24 @@ BPathFinder::FindPaths(path_base_directory baseDirectory, 
const char* subPath,
 
 /*static*/ status_t
 BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath,
+       uint32 flags, BStringList& paths)
+{
+       return FindPaths(NULL, baseDirectory, subPath, 0, paths);
+}
+
+
+/*static*/ status_t
+BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath,
        BStringList& paths)
 {
-       return FindPaths(baseDirectory, subPath, 0, paths);
+       return FindPaths(NULL, baseDirectory, subPath, 0, paths);
 }
 
 
 /*static*/ status_t
 BPathFinder::FindPaths(path_base_directory baseDirectory, BStringList& paths)
 {
-       return FindPaths(baseDirectory, NULL, 0, paths);
+       return FindPaths(NULL, baseDirectory, NULL, 0, paths);
 }
 
 
diff --git a/src/system/libroot/os/Architecture.cpp 
b/src/system/libroot/os/Architecture.cpp
new file mode 100644
index 0000000..9b96256
--- /dev/null
+++ b/src/system/libroot/os/Architecture.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <architecture_private.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <OS.h>
+
+#include <directories.h>
+#include <find_directory_private.h>
+#include <runtime_loader.h>
+
+
+static const char* const kArchitecture = B_HAIKU_ABI_NAME;
+static const char* const kPrimaryArchitecture = __HAIKU_PRIMARY_PACKAGING_ARCH;
+
+#ifdef __HAIKU_ARCH_X86
+       static const char* const kSiblingArchitectures[] = {"x86_gcc2", "x86"};
+#else
+       static const char* const kSiblingArchitectures[] = {};
+#endif
+
+static const size_t kSiblingArchitectureCount
+       = sizeof(kSiblingArchitectures) / sizeof(const char*);
+
+
+static bool
+has_secondary_architecture(const char* architecture)
+{
+       if (strcmp(architecture, kPrimaryArchitecture) == 0)
+               return false;
+
+       char path[B_PATH_NAME_LENGTH];
+       snprintf(path, sizeof(path), kSystemLibDirectory "/%s/libroot.so",
+               architecture);
+
+       struct stat st;
+       return lstat(path, &st) == 0;
+}
+
+
+// #pragma mark -
+
+
+const char*
+__get_architecture()
+{
+       return kArchitecture;
+}
+
+
+const char*
+__get_primary_architecture()
+{
+       return kPrimaryArchitecture;
+}
+
+
+size_t
+__get_secondary_architectures(const char** architectures, size_t count)
+{
+       size_t index = 0;
+
+       // If this is an architecture that could be a primary or secondary
+       // architecture, check for which architectures a libroot.so is present.
+       if (kSiblingArchitectureCount > 0) {
+               for (size_t i = 0; i < kSiblingArchitectureCount; i++) {
+                       const char* architecture = kSiblingArchitectures[i];
+                       if (!has_secondary_architecture(architecture))
+                               continue;
+
+                       if (index < count)
+                               architectures[index] = architecture;
+                       index++;
+               }
+       }
+
+       return index;
+}
+
+
+const char*
+__guess_architecture_for_path(const char* path)
+{
+       if (kSiblingArchitectureCount == 0)
+               return kPrimaryArchitecture;
+
+       // ask the runtime loader
+       const char* architecture;
+       if (__gRuntimeLoader->get_executable_architecture(path, &architecture)
+                       == B_OK) {
+               // verify that it is one of the sibling architectures
+               for (size_t i = 0; i < kSiblingArchitectureCount; i++) {
+                       if (strcmp(architecture, kSiblingArchitectures[i]) == 0)
+                               return kSiblingArchitectures[i];
+               }
+       }
+
+       // guess from the given path
+       architecture = __guess_secondary_architecture_from_path(path,
+               kSiblingArchitectures, kSiblingArchitectureCount);
+
+       return architecture != NULL && has_secondary_architecture(architecture)
+               ? architecture : kPrimaryArchitecture;
+}
+
+
+B_DEFINE_WEAK_ALIAS(__get_architecture, get_architecture);
+B_DEFINE_WEAK_ALIAS(__get_primary_architecture, get_primary_architecture);
+B_DEFINE_WEAK_ALIAS(__get_secondary_architectures, 
get_secondary_architectures);
+B_DEFINE_WEAK_ALIAS(__guess_architecture_for_path, 
guess_architecture_for_path);
diff --git a/src/system/libroot/os/Jamfile b/src/system/libroot/os/Jamfile
index 9e5809a..1b2b30c 100644
--- a/src/system/libroot/os/Jamfile
+++ b/src/system/libroot/os/Jamfile
@@ -14,6 +14,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
                SEARCH_SOURCE += [ FDirName $(SUBDIR) locks ] ;
 
                MergeObject <$(architecture)>os_main.o :
+                       Architecture.cpp
                        area.c
                        atomic.c
                        debug.c
diff --git a/src/system/libroot/os/find_paths.cpp 
b/src/system/libroot/os/find_paths.cpp
index 384f4cd..f3360a2 100644
--- a/src/system/libroot/os/find_paths.cpp
+++ b/src/system/libroot/os/find_paths.cpp
@@ -11,8 +11,11 @@
 #include <string.h>
 #include <sys/stat.h>
 
+#include <algorithm>
+
 #include <fs_attr.h>
 
+#include <architecture_private.h>
 #include <AutoDeleter.h>
 #include <syscalls.h>
 
@@ -28,7 +31,70 @@ static size_t kHomeInstallationLocationIndex = 1;
 static size_t kInstallationLocationCount
        = sizeof(kInstallationLocations) / sizeof(kInstallationLocations[0]);
 
+static const path_base_directory kArchitectureSpecificBaseDirectories[] = {
+       B_FIND_PATH_ADD_ONS_DIRECTORY,
+       B_FIND_PATH_BIN_DIRECTORY,
+       B_FIND_PATH_DEVELOP_LIB_DIRECTORY,
+       B_FIND_PATH_HEADERS_DIRECTORY,
+};
+
+static size_t kArchitectureSpecificBaseDirectoryCount =
+       sizeof(kArchitectureSpecificBaseDirectories)
+               / sizeof(kArchitectureSpecificBaseDirectories[0]);
+
+
+namespace {
+
+struct PathBuffer {
+       PathBuffer(char* buffer, size_t size)
+               :
+               fBuffer(buffer),
+               fSize(size),
+               fLength(0)
+       {
+               if (fSize > 0)
+                       fBuffer[0] = '\0';
+       }
+
+       bool Append(const char* toAppend, size_t length)
+       {
+               if (fLength < fSize) {
+                       size_t toCopy = std::min(length, fSize - fLength);
+                       if (toCopy > 0) {
+                               memcpy(fBuffer + fLength, toAppend, toCopy);
+                               fBuffer[fLength + toCopy] = '\0';
+                       }
+               }
+
+               fLength += length;
+               return fLength < fSize;
+       }
+
+       bool Append(const char* toAppend)
+       {
+               return Append(toAppend, strlen(toAppend));
+       }
+
+       size_t Length() const
+       {
+               return fLength;
+       }
+
+private:
+       char*   fBuffer;
+       size_t  fSize;
+       size_t  fLength;
+};
+
+}
+
 
+
+/*!    Returns the installation location relative path for the given base 
directory
+       constant and installation location index. A '%' in the returned path 
must be
+       replaced by "" for the primary architecture and by "/<arch>" for a 
secondary
+       architecture.
+ */
 static const char*
 get_relative_directory_path(size_t installationLocationIndex,
        path_base_directory baseDirectory)
@@ -37,11 +103,11 @@ get_relative_directory_path(size_t 
installationLocationIndex,
                case B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY:
                        return "";
                case B_FIND_PATH_ADD_ONS_DIRECTORY:
-                       return "/add-ons";
+                       return "/add-ons%";
                case B_FIND_PATH_APPS_DIRECTORY:
                        return "/apps";
                case B_FIND_PATH_BIN_DIRECTORY:
-                       return "/bin";
+                       return "/bin%";
                case B_FIND_PATH_BOOT_DIRECTORY:
                        return "/boot";
                case B_FIND_PATH_CACHE_DIRECTORY:
@@ -51,7 +117,7 @@ get_relative_directory_path(size_t installationLocationIndex,
                case B_FIND_PATH_DEVELOP_DIRECTORY:
                        return "/develop";
                case B_FIND_PATH_DEVELOP_LIB_DIRECTORY:
-                       return "/develop/lib";
+                       return "/develop/lib%";
                case B_FIND_PATH_DOCUMENTATION_DIRECTORY:
                        return "/documentation";
                case B_FIND_PATH_ETC_DIRECTORY:
@@ -59,7 +125,7 @@ get_relative_directory_path(size_t installationLocationIndex,
                case B_FIND_PATH_FONTS_DIRECTORY:
                        return "/data/fonts";
                case B_FIND_PATH_HEADERS_DIRECTORY:
-                       return "/develop/headers";
+                       return "/develop/headers%";
                case B_FIND_PATH_LIB_DIRECTORY:
                        return "/lib";
                case B_FIND_PATH_LOG_DIRECTORY:
@@ -80,7 +146,7 @@ get_relative_directory_path(size_t installationLocationIndex,
                case B_FIND_PATH_SPOOL_DIRECTORY:
                        return "/var/spool";
                case B_FIND_PATH_TRANSLATORS_DIRECTORY:
-                       return "/add-ons/Translators";
+                       return "/add-ons%/Translators";
                case B_FIND_PATH_VAR_DIRECTORY:
                        return "/var";
 
@@ -183,6 +249,73 @@ normalize_path(const char* path, char* buffer, size_t 
bufferSize)
 }
 
 
+static status_t
+normalize_longest_existing_path_prefix(const char* path, char* buffer,
+       size_t bufferSize)
+{
+       if (strlcpy(buffer, path, bufferSize) >= bufferSize)
+               return B_NAME_TOO_LONG;
+
+       // Until we have an existing path, chop off leaf components.
+       for (;;) {
+               struct stat st;
+               if (lstat(buffer, &st) == 0)
+                       break;
+
+               // Chop off the leaf, but fail, it it's "..", since then we'd 
actually
+               // construct a subpath.
+               char* lastSlash = strrchr(buffer, '/');
+               if (lastSlash == NULL || strcmp(lastSlash + 1, "..") == 0)
+                       return B_ENTRY_NOT_FOUND;
+
+               *lastSlash = '\0';
+       }
+
+       // normalize the existing prefix path
+       size_t prefixLength = strlen(buffer);
+       status_t error = normalize_path(buffer, buffer, bufferSize);
+       if (error != B_OK)
+               return error;
+
+       // Re-append the non-existent suffix. Remove duplicate slashes and "."
+       // components.
+       const char* bufferEnd = buffer + bufferSize;
+       char* end = buffer + strlen(buffer);
+       const char* remainder = path + prefixLength + 1;
+       while (*remainder != '\0') {
+               // find component start
+               if (*remainder == '/') {
+                       remainder++;
+                       continue;
+               }
+
+               // find component end
+               const char* componentEnd = strchr(remainder, '/');
+               if (componentEnd == NULL)
+                       componentEnd = remainder + strlen(remainder);
+
+               // skip "." components
+               size_t componentLength = componentEnd - remainder;
+               if (componentLength == 1 && *remainder == '.') {
+                       remainder++;
+                       continue;
+               }
+
+               // append the component
+               if (end + 1 + componentLength >= bufferEnd)
+                       return B_BUFFER_OVERFLOW;
+
+               *end++ = '/';
+               memcpy(end, remainder, componentLength);
+               end += componentLength;
+               remainder += componentLength;
+       }
+
+       *end = '\0';
+       return B_OK;
+}
+
+
 static const char*
 get_installation_location(const char* path, size_t& _index)
 {
@@ -238,21 +371,38 @@ normalize_dependency(const char* dependency, char* 
buffer, size_t bufferSize)
 
 
 static ssize_t
-process_path(const char* installationLocation, const char* relativePath,
-       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize)
+process_path(const char* installationLocation, const char* architecture,
+       const char* relativePath, const char* subPath, uint32 flags,
+       char* pathBuffer, size_t bufferSize)
 {
-       size_t totalLength;
+       // copy the installation location
+       PathBuffer buffer(pathBuffer, bufferSize);
+       buffer.Append(installationLocation);
+
+       // append the relative path, expanding the architecture placeholder
+       if (const char* placeholder = strchr(relativePath, '%')) {
+               buffer.Append(relativePath, placeholder - relativePath);
+
+               if (architecture != NULL) {
+                       buffer.Append("/", 1);
+                       buffer.Append(architecture);
+               }
+
+               buffer.Append(placeholder + 1);
+       } else
+               buffer.Append(relativePath);
+
+       // append subpath, if given
        if (subPath != NULL) {
-               totalLength = snprintf(pathBuffer, bufferSize, "%s%s/%s",
-                       installationLocation, relativePath, subPath);
-       } else {
-               totalLength = snprintf(pathBuffer, bufferSize, "%s%s",
-                       installationLocation, relativePath);
+               buffer.Append("/", 1);
+               buffer.Append(subPath);
        }
 
+       size_t totalLength = buffer.Length();
        if (totalLength >= bufferSize)
                return B_BUFFER_OVERFLOW;
 
+       // handle the flags
        char* path = pathBuffer;
 
        status_t error = B_OK;
@@ -283,9 +433,13 @@ process_path(const char* installationLocation, const char* 
relativePath,
 
 status_t
 internal_path_for_path(char* referencePath, size_t referencePathSize,
-       const char* dependency, path_base_directory baseDirectory,
-       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize)
+       const char* dependency, const char* architecture,
+       path_base_directory baseDirectory, const char* subPath, uint32 flags,
+       char* pathBuffer, size_t bufferSize)
 {
+       if (strcmp(architecture, __get_primary_architecture()) == 0)
+               architecture = NULL;
+
        // normalize
        status_t error = normalize_path(referencePath, referencePath,
                referencePathSize);
@@ -359,8 +513,8 @@ internal_path_for_path(char* referencePath, size_t 
referencePathSize,
        if (relativePath == NULL)
                return B_BAD_VALUE;
 
-       ssize_t pathSize = process_path(installationLocation, relativePath, 
subPath,
-               flags, pathBuffer, bufferSize);
+       ssize_t pathSize = process_path(installationLocation, architecture,
+               relativePath, subPath, flags, pathBuffer, bufferSize);
        if (pathSize <= 0)
                return pathSize == 0 ? B_ENTRY_NOT_FOUND : pathSize;
        return B_OK;
@@ -371,9 +525,18 @@ internal_path_for_path(char* referencePath, size_t 
referencePathSize,
 
 
 status_t
-__find_path(const void* codePointer, const char* dependency,
-       path_base_directory baseDirectory, const char* subPath, uint32 flags,
-       char* pathBuffer, size_t bufferSize)
+__find_path(const void* codePointer, path_base_directory baseDirectory,
+       const char* subPath, char* pathBuffer, size_t bufferSize)
+{
+       return __find_path_etc(codePointer, NULL, NULL, baseDirectory, subPath, 
0,
+               pathBuffer, bufferSize);
+}
+
+
+status_t
+__find_path_etc(const void* codePointer, const char* dependency,
+       const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize)
 {
        if (pathBuffer == NULL)
                return B_BAD_VALUE;
@@ -384,15 +547,28 @@ __find_path(const void* codePointer, const char* 
dependency,
        if (error != B_OK)
                return error;
 
+       if (architecture == NULL)
+               architecture = __get_architecture();
+
        return internal_path_for_path(imageInfo.name, sizeof(imageInfo.name),
-               dependency, baseDirectory, subPath, flags, pathBuffer, 
bufferSize);
+               dependency, architecture, baseDirectory, subPath, flags, 
pathBuffer,
+               bufferSize);
 }
 
 
 status_t
-__find_path_for_path(const char* path, const char* dependency,
-       path_base_directory baseDirectory, const char* subPath, uint32 flags,
-       char* pathBuffer, size_t bufferSize)
+__find_path_for_path(const char* path, path_base_directory baseDirectory,
+       const char* subPath, char* pathBuffer, size_t bufferSize)
+{
+       return __find_path_for_path_etc(path, NULL, NULL, baseDirectory, 
subPath, 0,
+               pathBuffer, bufferSize);
+}
+
+
+status_t
+__find_path_for_path_etc(const char* path, const char* dependency,
+       const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize)
 {
        char referencePath[B_PATH_NAME_LENGTH];
        if (strlcpy(referencePath, path, sizeof(referencePath))
@@ -400,18 +576,42 @@ __find_path_for_path(const char* path, const char* 
dependency,
                return B_NAME_TOO_LONG;
        }
 
+       if (architecture == NULL)
+               architecture = __guess_architecture_for_path(path);
+
        return internal_path_for_path(referencePath, sizeof(referencePath),
-               dependency, baseDirectory, subPath, flags, pathBuffer, 
bufferSize);
+               dependency, architecture, baseDirectory, subPath, flags, 
pathBuffer,
+               bufferSize);
 }
 
 
 status_t
 __find_paths(path_base_directory baseDirectory, const char* subPath,
-       uint32 flags, char*** _paths, size_t* _pathCount)
+       char*** _paths, size_t* _pathCount)
+{
+       return __find_paths_etc(NULL, baseDirectory, subPath, 0, _paths,
+               _pathCount);
+}
+
+
+status_t
+__find_paths_etc(const char* architecture, path_base_directory baseDirectory,
+       const char* subPath, uint32 flags, char*** _paths, size_t* _pathCount)
 {
        if (_paths == NULL || _pathCount == NULL)
                return B_BAD_VALUE;
 
+       // Analyze architecture. If NULL, use the caller's architecture. If the
+       // effective architecture is the primary one, set architecture to NULL 
to
+       // indicate that we don't need to insert an architecture subdirectory
+       // component.
+       if (architecture == NULL)
+               architecture = __get_architecture();
+       if (strcmp(architecture, __get_primary_architecture()) == 0)
+               architecture = NULL;
+       size_t architectureSize = architecture != NULL
+               ? strlen(architecture) + 1 : 0;
+
        size_t subPathLength = subPath != NULL ? strlen(subPath) + 1 : 0;
 
        // Get the relative paths and compute the total size to allocate.
@@ -425,6 +625,8 @@ __find_paths(path_base_directory baseDirectory, const char* 
subPath,
 
                totalSize += strlen(kInstallationLocations[i])
                        + strlen(relativePaths[i]) + subPathLength + 1;
+               if (strchr(relativePaths[i], '%') != NULL)
+                       totalSize += architectureSize - 1;
        }
 
        // allocate storage
@@ -440,7 +642,7 @@ __find_paths(path_base_directory baseDirectory, const char* 
subPath,
        const char* pathBufferEnd = pathBuffer + totalSize;
        for (size_t i = 0; i < kInstallationLocationCount; i++) {
                ssize_t pathSize = process_path(kInstallationLocations[i],
-                       relativePaths[i], subPath, flags, pathBuffer,
+                       architecture, relativePaths[i], subPath, flags, 
pathBuffer,
                        pathBufferEnd - pathBuffer);
                if (pathSize < 0)
                        return pathSize;
@@ -461,6 +663,65 @@ __find_paths(path_base_directory baseDirectory, const 
char* subPath,
 }
 
 
+const char*
+__guess_secondary_architecture_from_path(const char* path,
+       const char* const* secondaryArchitectures,
+       size_t secondaryArchitectureCount)
+{
+       // Get the longest existing prefix path and normalize it.
+       char prefix[B_PATH_NAME_LENGTH];
+       if (normalize_longest_existing_path_prefix(path, prefix, sizeof(prefix))
+                       != B_OK) {
+               return NULL;
+       }
+
+       // get an installation location relative path
+       size_t installationLocationIndex;
+       const char* installationLocation = get_installation_location(prefix,
+               installationLocationIndex);
+       if (installationLocation == NULL)
+               return NULL;
+
+       const char* relativePath = prefix + strlen(installationLocation);
+       if (relativePath[0] != '/')
+               return NULL;
+
+       // Iterate through the known paths that would indicate a secondary
+       // architecture and try to match them with our given path.
+       for (size_t i = 0; i < kArchitectureSpecificBaseDirectoryCount; i++) {
+               const char* basePath = get_relative_directory_path(
+                       installationLocationIndex, 
kArchitectureSpecificBaseDirectories[i]);
+               const char* placeholder = strchr(basePath, '%');
+               if (placeholder == NULL)
+                       continue;
+
+               // match the part up to the architecture placeholder
+               size_t prefixLength = placeholder - basePath;
+               if (strncmp(relativePath, basePath, prefixLength) != 0
+                       || relativePath[prefixLength] != '/') {
+                       continue;
+               }
+
+               // match the architecture
+               const char* architecturePart = relativePath + prefixLength + 1;
+               for (size_t k = 0; k < secondaryArchitectureCount; k++) {
+                       const char* architecture = secondaryArchitectures[k];
+                       size_t architectureLength = strlen(architecture);
+                       if (strncmp(architecturePart, architecture, 
architectureLength) == 0
+                               && (architecturePart[architectureLength] == '/'
+                                       || architecturePart[architectureLength] 
== '\0')) {
+                               return architecture;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+
 B_DEFINE_WEAK_ALIAS(__find_path, find_path);
+B_DEFINE_WEAK_ALIAS(__find_path_etc, find_path_etc);
 B_DEFINE_WEAK_ALIAS(__find_path_for_path, find_path_for_path);
+B_DEFINE_WEAK_ALIAS(__find_path_for_path_etc, find_path_for_path_etc);
 B_DEFINE_WEAK_ALIAS(__find_paths, find_paths);
+B_DEFINE_WEAK_ALIAS(__find_paths_etc, find_paths_etc);

############################################################################

Commit:      2c2f3ab4e1b8dd6b043cb571384c25746b53e4a4
URL:         http://cgit.haiku-os.org/haiku/commit/?id=2c2f3ab
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sat Nov 16 21:28:36 2013 UTC

findpaths: Add an -a <architecture> option

----------------------------------------------------------------------------

diff --git a/src/bin/findpaths.cpp b/src/bin/findpaths.cpp
index 5b99632..607f9f4 100644
--- a/src/bin/findpaths.cpp
+++ b/src/bin/findpaths.cpp
@@ -92,6 +92,12 @@ static const char* kUsage =
        "modify this behavior.\n"
        "\n"
        "Options:\n"
+       "  -a <architecture>\n"
+       "    If the path(s) specified by <kind> are architecture specific, 
use\n"
+       "    architecture <architecture>. If not specified, the primary\n"
+       "    architecture is used, unless the -p/--path option is specified, 
in\n"
+       "    which case the architecture associated with the given <path> is\n"
+       "    used.\n"
        "  -c <separator>\n"
        "    Concatenate the resulting paths, separated only by <separator>,\n"
        "    instead of printing a path per line.\n"
@@ -123,6 +129,7 @@ print_usage_and_exit(bool error)
 int
 main(int argc, const char* const* argv)
 {
+       const char* architecture = NULL;
        const char* dependency = NULL;
        const char* referencePath = NULL;
        bool existingOnly = false;
@@ -130,6 +137,7 @@ main(int argc, const char* const* argv)
 
        while (true) {
                static struct option sLongOptions[] = {
+                       { "architecture", required_argument, 0, 'a' },
                        { "dependency", required_argument, 0, 'd' },
                        { "help", no_argument, 0, 'h' },
                        { "path", required_argument, 0, 'p' },
@@ -137,12 +145,16 @@ main(int argc, const char* const* argv)
                };
 
                opterr = 0; // don't print errors
-               int c = getopt_long(argc, (char**)argv, "+c:d:ehlp:",
+               int c = getopt_long(argc, (char**)argv, "+a:c:d:ehlp:",
                        sLongOptions, NULL);
                if (c == -1)
                        break;
 
                switch (c) {
+                       case 'a':
+                               architecture = optarg;
+                               break;
+
                        case 'c':
                                separator = optarg;
                                break;
@@ -208,7 +220,7 @@ main(int argc, const char* const* argv)
        if (referencePath != NULL) {
                BPath path;
                status_t error = BPathFinder(referencePath, 
dependency).FindPath(
-                       baseDirectory, subPath,
+                       architecture, baseDirectory, subPath,
                        existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, path);
                if (error != B_OK) {
                        fprintf(stderr, "Error: Failed to find path: %s\n",
@@ -219,8 +231,8 @@ main(int argc, const char* const* argv)
                printf("%s\n", path.Path());
        } else {
                BStringList paths;
-               status_t error = BPathFinder::FindPaths(baseDirectory, subPath,
-                       existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, paths);
+               status_t error = BPathFinder::FindPaths(architecture, 
baseDirectory,
+                       subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, 
paths);
                if (error != B_OK) {
                        fprintf(stderr, "Error: Failed to find paths: %s\n",
                                strerror(error));

############################################################################

Commit:      c39c9283aa34b0b694e61c9edbd0a8fb1d490d93
URL:         http://cgit.haiku-os.org/haiku/commit/?id=c39c928
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sun Nov 17 01:04:31 2013 UTC

Add get_architectures() and C++ versions

* get_architectures() returns the primary and the secondary
  architectures in one array. That turned out to be convenient.
* Add C++ versions for get[_secondary]_architectures(), returning a
  BStringList.

----------------------------------------------------------------------------

diff --git a/headers/os/support/Architecture.h 
b/headers/os/support/Architecture.h
index 7781397..5ed8bc7 100644
--- a/headers/os/support/Architecture.h
+++ b/headers/os/support/Architecture.h
@@ -18,10 +18,25 @@ const char* get_architecture();
 const char*    get_primary_architecture();
 size_t         get_secondary_architectures(const char** architectures,
                                size_t count);
+size_t         get_architectures(const char** architectures, size_t count);
 const char*    guess_architecture_for_path(const char* path);
 
 
 __END_DECLS
 
 
+/* C++ API */
+#ifdef __cplusplus
+
+
+#include <StringList.h>
+
+
+status_t       get_secondary_architectures(BStringList& _architectures);
+status_t       get_architectures(BStringList& _architectures);
+
+
+#endif
+
+
 #endif /* _SUPPORT_ARCHITECTURE_H */
diff --git a/headers/private/system/architecture_private.h 
b/headers/private/system/architecture_private.h
index e638375..1000537 100644
--- a/headers/private/system/architecture_private.h
+++ b/headers/private/system/architecture_private.h
@@ -16,6 +16,7 @@ const char*   __get_architecture();
 const char*    __get_primary_architecture();
 size_t         __get_secondary_architectures(const char** architectures,
                                size_t count);
+size_t         __get_architectures(const char** architectures, size_t count);
 const char*    __guess_architecture_for_path(const char* path);
 
 
diff --git a/src/kits/support/Architecture.cpp 
b/src/kits/support/Architecture.cpp
new file mode 100644
index 0000000..93afc16
--- /dev/null
+++ b/src/kits/support/Architecture.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <Architecture.h>
+
+#include <algorithm>
+
+#include <StringList.h>
+
+
+static const size_t kMaxArchitectureCount = 16;
+
+
+static status_t
+string_array_to_string_list(const char* const* architectures, size_t count,
+       BStringList& _architectures)
+{
+       _architectures.MakeEmpty();
+
+       for (size_t i = 0; i < count; i++) {
+               BString architecture(architectures[i]);
+               if (architecture.IsEmpty() || 
!_architectures.Add(architecture)) {
+                       _architectures.MakeEmpty();
+                       return B_NO_MEMORY;
+               }
+       }
+
+       return B_OK;
+}
+
+
+status_t
+get_secondary_architectures(BStringList& _architectures)
+{
+       const char* architectures[kMaxArchitectureCount];
+       size_t count = get_secondary_architectures(architectures,
+               kMaxArchitectureCount);
+       return string_array_to_string_list(architectures,
+               std::min(count, kMaxArchitectureCount), _architectures);
+}
+
+
+status_t
+get_architectures(BStringList& _architectures)
+{
+       const char* architectures[kMaxArchitectureCount];
+       size_t count = get_architectures(architectures, kMaxArchitectureCount);
+       return string_array_to_string_list(architectures,
+               std::min(count, kMaxArchitectureCount), _architectures);
+}
diff --git a/src/kits/support/Jamfile b/src/kits/support/Jamfile
index a6e8249..e2ac639 100644
--- a/src/kits/support/Jamfile
+++ b/src/kits/support/Jamfile
@@ -10,6 +10,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
                local architecture = $(TARGET_PACKAGING_ARCH) ;
 
                MergeObject <libbe!$(architecture)>support_kit.o :
+                       Architecture.cpp
                        Archivable.cpp
                        ArchivingManagers.cpp
                        Beep.cpp
diff --git a/src/system/libroot/os/Architecture.cpp 
b/src/system/libroot/os/Architecture.cpp
index 9b96256..d0a849c 100644
--- a/src/system/libroot/os/Architecture.cpp
+++ b/src/system/libroot/os/Architecture.cpp
@@ -85,6 +85,17 @@ __get_secondary_architectures(const char** architectures, 
size_t count)
 }
 
 
+size_t
+__get_architectures(const char** architectures, size_t count)
+{
+       if (count == 0)
+               return __get_secondary_architectures(NULL, 0) + 1;
+
+       architectures[0] = __get_primary_architecture();
+       return __get_secondary_architectures(architectures + 1, count -1) + 1;
+}
+
+
 const char*
 __guess_architecture_for_path(const char* path)
 {
@@ -114,4 +125,5 @@ __guess_architecture_for_path(const char* path)
 B_DEFINE_WEAK_ALIAS(__get_architecture, get_architecture);
 B_DEFINE_WEAK_ALIAS(__get_primary_architecture, get_primary_architecture);
 B_DEFINE_WEAK_ALIAS(__get_secondary_architectures, 
get_secondary_architectures);
+B_DEFINE_WEAK_ALIAS(__get_architectures, get_architectures);
 B_DEFINE_WEAK_ALIAS(__guess_architecture_for_path, 
guess_architecture_for_path);

############################################################################

Revision:    hrev46378
Commit:      4f5e93857671d231372096457d024926635dcee6
URL:         http://cgit.haiku-os.org/haiku/commit/?id=4f5e938
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Sun Nov 17 01:05:23 2013 UTC

Add setarch and getarch commands

----------------------------------------------------------------------------

diff --git a/build/jam/images/HaikuImage b/build/jam/images/HaikuImage
index 74bfa6d..9ecd191 100644
--- a/build/jam/images/HaikuImage
+++ b/build/jam/images/HaikuImage
@@ -14,7 +14,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
        echo eject env error expand expr
        factor false fdinfo ffm filepanel find finddir findpaths 
FirstBootPrompt fmt
        fold fortune frcode fstrim ftp ftpd funzip fwcontrol@x86
-       gawk gdb@x86 getlimits groupadd groupdel groupmod groups gzip gzexe
+       gawk gdb@x86 getarch getlimits groupadd groupdel groupmod groups gzip 
gzexe
        hd head hey hostname
        id ident ifconfig <bin>install installsound iroster isvolume
        ideinfo@ide idestatus@ide
@@ -31,9 +31,9 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
        query quit
        rc readlink reindex release renice rlog rm rmattr rmindex rmdir roster
        route
-       safemode screen_blanker screenmode screenshot sdiff setdecor setmime 
settype
-       setversion setvolume seq sha1sum sha256sum shar shred shuf shutdown 
sleep
-       sort spamdbm split stat strace stty su sum sync sysinfo
+       safemode screen_blanker screenmode screenshot sdiff setarch setdecor 
setmime
+       settype setversion setvolume seq sha1sum sha256sum shar shred shuf 
shutdown
+       sleep sort spamdbm split stat strace stty su sum sync sysinfo
        tac tail tcpdump tcptester tee telnet telnetd test timeout top touch
        tr traceroute translate trash true truncate tsort tty
        uname unchop unexpand unmount uniq unlink unshar unzip unzipsfx
diff --git a/build/jam/images/HaikuImageBootstrap 
b/build/jam/images/HaikuImageBootstrap
index 9ea5d4d..8bb57e9 100644
--- a/build/jam/images/HaikuImageBootstrap
+++ b/build/jam/images/HaikuImageBootstrap
@@ -14,7 +14,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
        echo eject env error expand expr
        factor false fdinfo ffm filepanel find finddir findpaths fmt fold
        fortune frcode ftp ftpd funzip
-       gawk gdb@x86 getlimits groupadd groupdel groupmod groups gzip gzexe
+       gawk gdb@x86 getarch getlimits groupadd groupdel groupmod groups gzip 
gzexe
        hd head hey hostname
        id ident ifconfig <bin>install isvolume
        ideinfo@ide idestatus@ide
@@ -31,7 +31,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
        query quit
        rc readlink reindex release renice rlog rm rmattr rmindex rmdir roster
        route
-       safemode screen_blanker screenmode sdiff setmime settype
+       safemode screen_blanker screenmode sdiff setarch setmime settype
        setversion setvolume seq sha1sum sha256sum shar shred shuf shutdown 
sleep
        sort split stat strace stty su sum sync sysinfo
        tac tail tcpdump tcptester tee telnet telnetd test timeout top touch
diff --git a/src/bin/Jamfile b/src/bin/Jamfile
index e2fb698..eb7c6b2 100644
--- a/src/bin/Jamfile
+++ b/src/bin/Jamfile
@@ -116,9 +116,11 @@ StdBinCommands
        alert.cpp
        eject.cpp
        findpaths.cpp
+       getarch.cpp
        hey.cpp
        reindex.cpp
        resattr.cpp
+       setarch.cpp
        setdecor.cpp
        settype.cpp
        spybmessage.cpp
diff --git a/src/bin/getarch.cpp b/src/bin/getarch.cpp
new file mode 100644
index 0000000..47a7fe6
--- /dev/null
+++ b/src/bin/getarch.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Architecture.h>
+#include <Path.h>
+#include <PathFinder.h>
+#include <StringList.h>
+
+
+extern const char* __progname;
+const char* kCommandName = __progname;
+
+
+static const char* kUsage =
+       "Usage: %s [ <options> ] [ <path> ]\n"
+       "Prints the architecture currently set via the PATH environment 
variable,\n"
+       "when no arguments are given. When <path> is specified, the 
architecture\n"
+       "associated with that path is printed. The options allow to print the\n"
+       "primary architecture or the secondary architectures.\n"
+       "\n"
+       "Options:\n"
+       "  -h, --help\n"
+       "    Print this usage info.\n"
+       "  -p, --primary\n"
+       "    Print the primary architecture.\n"
+       "  -s, --secondary\n"
+       "    Print all secondary architectures for which support is 
installed.\n"
+;
+
+
+static void
+print_usage_and_exit(bool error)
+{
+    fprintf(error ? stderr : stdout, kUsage, kCommandName);
+    exit(error ? 1 : 0);
+}
+
+
+static BString
+get_current_architecture()
+{
+       // get the system installation location path
+       BPath systemPath;
+       if (find_directory(B_SYSTEM_DIRECTORY, &systemPath) != B_OK)
+               return BString();
+
+       // get all architectures
+       BStringList architectures;
+       get_architectures(architectures);
+       if (architectures.CountStrings() < 2)
+               return BString();
+
+       // get the system bin directory for each architecture
+       BStringList binDirectories;
+       BPathFinder pathFinder(systemPath.Path());
+       int32 architectureCount = architectures.CountStrings();
+       for (int32 i = 0; i < architectureCount; i++) {
+               BPath path;
+               if (pathFinder.FindPath(architectures.StringAt(i),
+                               B_FIND_PATH_BIN_DIRECTORY, NULL, 0, path) != 
B_OK
+                       || !binDirectories.Add(path.Path())) {
+                       return BString();
+               }
+       }
+
+       // Get and split the PATH environmental variable value. The first system
+       // bin path we encounter implies the architecture.
+       char* pathVariableValue = getenv("PATH");
+       BStringList paths;
+       if (pathVariableValue != NULL
+               && BString(pathVariableValue).Split(":", true, paths)) {
+               int32 count = paths.CountStrings();
+               for (int32 i = 0; i < count; i++) {
+                       // normalize the path, but skip a relative one
+                       BPath path;
+                       if (paths.StringAt(i)[0] != '/'
+                               || path.SetTo(paths.StringAt(i), NULL, true) != 
B_OK) {
+                               continue;
+                       }
+
+                       int32 index = binDirectories.IndexOf(path.Path());
+                       if (index >= 0)
+                               return architectures.StringAt(index);
+               }
+       }
+
+       return BString();
+}
+
+
+int
+main(int argc, const char* const* argv)
+{
+       bool printPrimary = false;
+       bool printSecondary = false;
+
+       while (true) {
+               static struct option sLongOptions[] = {
+                       { "help", no_argument, 0, 'h' },
+                       { "primary", no_argument, 0, 'p' },
+                       { "secondary", no_argument, 0, 's' },
+                       { 0, 0, 0, 0 }
+               };
+
+               opterr = 0; // don't print errors
+               int c = getopt_long(argc, (char**)argv, "+hps",
+                       sLongOptions, NULL);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+                       case 'h':
+                               print_usage_and_exit(false);
+                               break;
+
+                       case 'p':
+                               printPrimary = true;
+                               break;
+
+                       case 's':
+                               printSecondary = true;
+                               break;
+
+                       default:
+                               print_usage_and_exit(true);
+                               break;
+               }
+       }
+
+       // The remaining argument is the optional path.
+       const char* path = optind < argc ? argv[optind++] : NULL;
+       if (optind < argc)
+               print_usage_and_exit(true);
+
+       // only one of path, printPrimary, printSecondary may be specified
+       if (int(path != NULL) + int(printPrimary) + int(printSecondary) > 1)
+               print_usage_and_exit(true);
+
+       if (path != NULL) {
+               // architecture for given path
+               printf("%s\n", guess_architecture_for_path(path));
+       } else if (printPrimary) {
+               // primary architecture
+               printf("%s\n", get_primary_architecture());
+       } else if (printSecondary) {
+               // secondary architectures
+               BStringList architectures;
+               get_secondary_architectures(architectures);
+               int32 count = architectures.CountStrings();
+               for (int32 i = 0; i < count; i++)
+                       printf("%s\n", architectures.StringAt(i).String());
+       } else {
+               // current architecture as implied by PATH
+               BString architecture = get_current_architecture();
+               printf("%s\n",
+                       architecture.IsEmpty()
+                               ? get_primary_architecture() : 
architecture.String());
+       }
+
+       return 0;
+}
diff --git a/src/bin/setarch.cpp b/src/bin/setarch.cpp
new file mode 100644
index 0000000..b6fc26c
--- /dev/null
+++ b/src/bin/setarch.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <errno.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <Architecture.h>
+#include <Path.h>
+#include <PathFinder.h>
+#include <StringList.h>
+
+
+extern const char* __progname;
+const char* kCommandName = __progname;
+
+
+static const char* kUsage =
+       "Usage: %s [ <options> ] <architecture> [ <command> ... ]\n"
+       "Executes the given command or, by default, a shell with a PATH\n"
+       "environment variable modified such that commands for the given\n"
+       "architecture will be preferred, respectively used exclusively in case 
of\n"
+       "the primary architecture.\n"
+       "\n"
+       "Options:\n"
+       "  -h, --help\n"
+       "    Print this usage info.\n"
+       "  -p, --print-path\n"
+       "    Only print the modified PATH variable value; don't execute any\n"
+       "    command.\n"
+;
+
+
+static void
+print_usage_and_exit(bool error)
+{
+    fprintf(error ? stderr : stdout, kUsage, kCommandName);
+    exit(error ? 1 : 0);
+}
+
+
+static bool
+is_primary_architecture(const char* architecture)
+{
+       return strcmp(architecture, get_primary_architecture()) == 0;
+}
+
+
+static void
+get_bin_directories(const char* architecture, BStringList& _directories)
+{
+       status_t error = BPathFinder::FindPaths(architecture,
+               B_FIND_PATH_BIN_DIRECTORY, NULL, 0, _directories);
+       if (error != B_OK) {
+               fprintf(stderr, "Error: Failed to get bin directories for 
architecture "
+                       "%s: %s\n", architecture, strerror(error));
+               exit(1);
+       }
+}
+
+
+static void
+compute_new_paths(const char* architecture, BStringList& _paths)
+{
+       // get the primary architecture bin paths
+       BStringList primaryBinDirectories;
+       get_bin_directories(get_primary_architecture(), primaryBinDirectories);
+
+       // get the bin paths to insert
+       BStringList binDirectoriesToInsert;
+       if (!is_primary_architecture(architecture))
+               get_bin_directories(architecture, binDirectoriesToInsert);
+
+       // split the PATH variable
+       char* pathVariableValue = getenv("PATH");
+       BStringList paths;
+       if (pathVariableValue != NULL
+               && !BString(pathVariableValue).Split(":", true, paths)) {
+               fprintf(stderr, "Error: Out of memory!\n");
+               exit(1);
+       }
+
+       // Filter the paths, removing any path that isn't associated with the
+       // primary architecture. Also find the insertion index for the 
architecture
+       // bin paths.
+       int32 insertionIndex = -1;
+       int32 count = paths.CountStrings();
+       for (int32 i = 0; i < count; i++) {
+               // We always keep relative paths. Filter absolute ones only.
+               const char* path = paths.StringAt(i);
+               if (path[0] == '/') {
+                       // try to normalize the path
+                       BPath normalizedPath;
+                       if (normalizedPath.SetTo(path, NULL, true) == B_OK)
+                               path = normalizedPath.Path();
+
+                       // Check, if this is a primary bin directory. If not, 
determine the
+                       // path's architecture.
+                       int32 index = primaryBinDirectories.IndexOf(path);
+                       if (index >= 0) {
+                               if (insertionIndex < 0)
+                                       insertionIndex = i;
+                       } else if (!is_primary_architecture(
+                                       guess_architecture_for_path(path))) {
+                               // a non-primary architecture path -- skip
+                               continue;
+                       }
+               }
+
+               if (!_paths.Add(paths.StringAt(i))) {
+                       fprintf(stderr, "Error: Out of memory!\n");
+                       exit(1);
+               }
+       }
+
+       // Insert the paths for the specified architecture, if any.
+       if (!binDirectoriesToInsert.IsEmpty()) {
+               if (!(insertionIndex < 0
+                               ? _paths.Add(binDirectoriesToInsert)
+                               : _paths.Add(binDirectoriesToInsert, 
insertionIndex))) {
+                       fprintf(stderr, "Error: Out of memory!\n");
+                       exit(1);
+               }
+       }
+}
+
+
+int
+main(int argc, const char* const* argv)
+{
+       bool printPath = false;
+
+       while (true) {
+               static struct option sLongOptions[] = {
+                       { "help", no_argument, 0, 'h' },
+                       { "print-path", no_argument, 0, 'p' },
+                       { 0, 0, 0, 0 }
+               };
+
+               opterr = 0; // don't print errors
+               int c = getopt_long(argc, (char**)argv, "+hp",
+                       sLongOptions, NULL);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+                       case 'h':
+                               print_usage_and_exit(false);
+                               break;
+
+                       case 'p':
+                               printPath = true;
+                               break;
+
+                       default:
+                               print_usage_and_exit(true);
+                               break;
+               }
+       }
+
+       // The remaining arguments are the architecture and optionally the 
command
+       // to execute.
+       if (optind >= argc)
+               print_usage_and_exit(true);
+       const char* architecture = optind < argc ? argv[optind++] : NULL;
+
+       int commandArgCount = argc - optind;
+       const char* const* commandArgs = commandArgCount > 0 ? argv + optind : 
NULL;
+
+       if (printPath && commandArgs != NULL)
+               print_usage_and_exit(true);
+
+       // check the architecture
+       BStringList architectures;
+       status_t error = get_architectures(architectures);
+       if (error != B_OK) {
+               fprintf(stderr, "Error: Failed to get architectures: %s\n",
+                       strerror(error));
+               exit(1);
+       }
+
+       if (!architectures.HasString(architecture)) {
+               fprintf(stderr, "Error: Unsupported architecture \"%s\"\n",
+                       architecture);
+               exit(1);
+       }
+
+       // get the new paths
+       BStringList paths;
+       compute_new_paths(architecture, paths);
+
+       BString pathVariableValue = paths.Join(":");
+       if (!paths.IsEmpty() && pathVariableValue.IsEmpty())
+               fprintf(stderr, "Error: Out of memory!\n");
+
+       if (printPath) {
+               printf("%s\n", pathVariableValue.String());
+               return 0;
+       }
+
+       // set PATH
+       if (setenv("PATH", pathVariableValue, 1) != 0) {
+               fprintf(stderr, "Error: Failed to set PATH: %s\n", 
strerror(errno));
+               exit(1);
+       }
+
+       // if no command is given, get the user's shell
+       const char* shellCommand[2];
+       if (commandArgs == NULL) {
+               struct passwd* pwd = getpwuid(geteuid());
+               shellCommand[0] = pwd != NULL ? pwd->pw_shell : "/bin/sh";
+               shellCommand[1] = NULL;
+               commandArgs = shellCommand;
+               commandArgCount = 1;
+       }
+
+       // exec the command
+       execvp(commandArgs[0], (char* const*)commandArgs);
+
+       fprintf(stderr, "Error: Executing \"%s\" failed: %s\n", commandArgs[0],
+               strerror(errno));
+       return 1;
+}


Other related posts: