xref: /haiku/src/bin/getarch.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*
2  * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <getopt.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <Architecture.h>
13 #include <Path.h>
14 #include <PathFinder.h>
15 #include <StringList.h>
16 
17 
18 extern const char* __progname;
19 const char* kCommandName = __progname;
20 
21 
22 static const char* kUsage =
23 	"Usage: %s [ <options> ] [ <path> ]\n"
24 	"Prints the architecture currently set via the PATH environment variable,\n"
25 	"when no arguments are given. When <path> is specified, the architecture\n"
26 	"associated with that path is printed. The options allow to print the\n"
27 	"primary architecture or the secondary architectures.\n"
28 	"\n"
29 	"Options:\n"
30 	"  -h, --help\n"
31 	"    Print this usage info.\n"
32 	"  -p, --primary\n"
33 	"    Print the primary architecture.\n"
34 	"  -s, --secondary\n"
35 	"    Print all secondary architectures for which support is installed.\n"
36 ;
37 
38 
39 static void
40 print_usage_and_exit(bool error)
41 {
42     fprintf(error ? stderr : stdout, kUsage, kCommandName);
43     exit(error ? 1 : 0);
44 }
45 
46 
47 static BString
48 get_current_architecture()
49 {
50 	// get the system installation location path
51 	BPath systemPath;
52 	if (find_directory(B_SYSTEM_DIRECTORY, &systemPath) != B_OK)
53 		return BString();
54 
55 	// get all architectures
56 	BStringList architectures;
57 	get_architectures(architectures);
58 	if (architectures.CountStrings() < 2)
59 		return BString();
60 
61 	// get the system bin directory for each architecture
62 	BStringList binDirectories;
63 	BPathFinder pathFinder(systemPath.Path());
64 	int32 architectureCount = architectures.CountStrings();
65 	for (int32 i = 0; i < architectureCount; i++) {
66 		BPath path;
67 		if (pathFinder.FindPath(architectures.StringAt(i),
68 				B_FIND_PATH_BIN_DIRECTORY, NULL, 0, path) != B_OK
69 			|| !binDirectories.Add(path.Path())) {
70 			return BString();
71 		}
72 	}
73 
74 	// Get and split the PATH environmental variable value. The first system
75 	// bin path we encounter implies the architecture.
76 	char* pathVariableValue = getenv("PATH");
77 	BStringList paths;
78 	if (pathVariableValue != NULL
79 		&& BString(pathVariableValue).Split(":", true, paths)) {
80 		int32 count = paths.CountStrings();
81 		for (int32 i = 0; i < count; i++) {
82 			// normalize the path, but skip a relative one
83 			BPath path;
84 			if (paths.StringAt(i)[0] != '/'
85 				|| path.SetTo(paths.StringAt(i), NULL, true) != B_OK) {
86 				continue;
87 			}
88 
89 			int32 index = binDirectories.IndexOf(path.Path());
90 			if (index >= 0)
91 				return architectures.StringAt(index);
92 		}
93 	}
94 
95 	return BString();
96 }
97 
98 
99 int
100 main(int argc, const char* const* argv)
101 {
102 	bool printPrimary = false;
103 	bool printSecondary = false;
104 
105 	while (true) {
106 		static struct option sLongOptions[] = {
107 			{ "help", no_argument, 0, 'h' },
108 			{ "primary", no_argument, 0, 'p' },
109 			{ "secondary", no_argument, 0, 's' },
110 			{ 0, 0, 0, 0 }
111 		};
112 
113 		opterr = 0; // don't print errors
114 		int c = getopt_long(argc, (char**)argv, "+hps",
115 			sLongOptions, NULL);
116 		if (c == -1)
117 			break;
118 
119 		switch (c) {
120 			case 'h':
121 				print_usage_and_exit(false);
122 				break;
123 
124 			case 'p':
125 				printPrimary = true;
126 				break;
127 
128 			case 's':
129 				printSecondary = true;
130 				break;
131 
132 			default:
133 				print_usage_and_exit(true);
134 				break;
135 		}
136 	}
137 
138 	// The remaining argument is the optional path.
139 	const char* path = optind < argc ? argv[optind++] : NULL;
140 	if (optind < argc)
141 		print_usage_and_exit(true);
142 
143 	// only one of path, printPrimary, printSecondary may be specified
144 	if (int(path != NULL) + int(printPrimary) + int(printSecondary) > 1)
145 		print_usage_and_exit(true);
146 
147 	if (path != NULL) {
148 		// architecture for given path
149 		printf("%s\n", guess_architecture_for_path(path));
150 	} else if (printPrimary) {
151 		// primary architecture
152 		printf("%s\n", get_primary_architecture());
153 	} else if (printSecondary) {
154 		// secondary architectures
155 		BStringList architectures;
156 		get_secondary_architectures(architectures);
157 		int32 count = architectures.CountStrings();
158 		for (int32 i = 0; i < count; i++)
159 			printf("%s\n", architectures.StringAt(i).String());
160 	} else {
161 		// current architecture as implied by PATH
162 		BString architecture = get_current_architecture();
163 		printf("%s\n",
164 			architecture.IsEmpty()
165 				? get_primary_architecture() : architecture.String());
166 	}
167 
168 	return 0;
169 }
170