Add setarch and getarch commands

This commit is contained in:
Ingo Weinhold 2013-11-17 02:05:23 +01:00
parent c39c9283aa
commit 4f5e938576
5 changed files with 407 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -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

169
src/bin/getarch.cpp Normal file
View File

@ -0,0 +1,169 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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;
}

230
src/bin/setarch.cpp Normal file
View File

@ -0,0 +1,230 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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;
}