1/*
2 * Copyright 2002, Sebastian Nozzi <sebnozzi@gmx.net>.
3 * Copyright 2004, Francois Revol.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8#include <stdio.h>
9#include <string.h>
10
11#include <FindDirectory.h>
12#include <fs_info.h>
13
14
15#define NO_ERRORS			0
16#define ARGUMENT_MISSING	1
17#define WRONG_DIR_TYPE		2
18
19typedef struct {
20	const char *key;
21	directory_which value;
22} directoryType;
23
24#define KEYVALUE_PAIR(key) {#key, key}
25
26directoryType directoryTypes[] = {
27	// Generic directories
28	KEYVALUE_PAIR(B_DESKTOP_DIRECTORY),
29	KEYVALUE_PAIR(B_TRASH_DIRECTORY),
30	KEYVALUE_PAIR(B_APPS_DIRECTORY),
31	KEYVALUE_PAIR(B_PACKAGE_LINKS_DIRECTORY),
32	KEYVALUE_PAIR(B_PREFERENCES_DIRECTORY),
33	KEYVALUE_PAIR(B_UTILITIES_DIRECTORY),
34
35	// System directories
36	KEYVALUE_PAIR(B_SYSTEM_DIRECTORY),
37	KEYVALUE_PAIR(B_SYSTEM_ADDONS_DIRECTORY),
38	KEYVALUE_PAIR(B_SYSTEM_BOOT_DIRECTORY),
39	KEYVALUE_PAIR(B_SYSTEM_FONTS_DIRECTORY),
40	KEYVALUE_PAIR(B_SYSTEM_LIB_DIRECTORY),
41	KEYVALUE_PAIR(B_SYSTEM_SERVERS_DIRECTORY),
42	KEYVALUE_PAIR(B_SYSTEM_APPS_DIRECTORY),
43	KEYVALUE_PAIR(B_SYSTEM_BIN_DIRECTORY),
44	KEYVALUE_PAIR(B_SYSTEM_DOCUMENTATION_DIRECTORY),
45	KEYVALUE_PAIR(B_SYSTEM_PREFERENCES_DIRECTORY),
46	KEYVALUE_PAIR(B_SYSTEM_TRANSLATORS_DIRECTORY),
47	KEYVALUE_PAIR(B_SYSTEM_MEDIA_NODES_DIRECTORY),
48	KEYVALUE_PAIR(B_SYSTEM_SOUNDS_DIRECTORY),
49	KEYVALUE_PAIR(B_SYSTEM_DATA_DIRECTORY),
50	KEYVALUE_PAIR(B_SYSTEM_DEVELOP_DIRECTORY),
51	KEYVALUE_PAIR(B_SYSTEM_PACKAGES_DIRECTORY),
52	KEYVALUE_PAIR(B_SYSTEM_HEADERS_DIRECTORY),
53
54	// Common directories
55	KEYVALUE_PAIR(B_COMMON_DIRECTORY),
56	KEYVALUE_PAIR(B_COMMON_SYSTEM_DIRECTORY),
57	KEYVALUE_PAIR(B_COMMON_ADDONS_DIRECTORY),
58	KEYVALUE_PAIR(B_COMMON_BOOT_DIRECTORY),
59	KEYVALUE_PAIR(B_COMMON_FONTS_DIRECTORY),
60	KEYVALUE_PAIR(B_COMMON_LIB_DIRECTORY),
61	KEYVALUE_PAIR(B_COMMON_SERVERS_DIRECTORY),
62	KEYVALUE_PAIR(B_COMMON_BIN_DIRECTORY),
63	KEYVALUE_PAIR(B_COMMON_ETC_DIRECTORY),
64	KEYVALUE_PAIR(B_COMMON_DOCUMENTATION_DIRECTORY),
65	KEYVALUE_PAIR(B_COMMON_SETTINGS_DIRECTORY),
66	KEYVALUE_PAIR(B_COMMON_DEVELOP_DIRECTORY),
67	KEYVALUE_PAIR(B_COMMON_LOG_DIRECTORY),
68	KEYVALUE_PAIR(B_COMMON_SPOOL_DIRECTORY),
69	KEYVALUE_PAIR(B_COMMON_TEMP_DIRECTORY),
70	KEYVALUE_PAIR(B_COMMON_VAR_DIRECTORY),
71	KEYVALUE_PAIR(B_COMMON_TRANSLATORS_DIRECTORY),
72	KEYVALUE_PAIR(B_COMMON_MEDIA_NODES_DIRECTORY),
73	KEYVALUE_PAIR(B_COMMON_SOUNDS_DIRECTORY),
74	KEYVALUE_PAIR(B_COMMON_DATA_DIRECTORY),
75	KEYVALUE_PAIR(B_COMMON_CACHE_DIRECTORY),
76	KEYVALUE_PAIR(B_COMMON_PACKAGES_DIRECTORY),
77	KEYVALUE_PAIR(B_COMMON_HEADERS_DIRECTORY),
78	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DIRECTORY),
79	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_ADDONS_DIRECTORY),
80	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_TRANSLATORS_DIRECTORY),
81	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_MEDIA_NODES_DIRECTORY),
82	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_BIN_DIRECTORY),
83	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DATA_DIRECTORY),
84	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_FONTS_DIRECTORY),
85	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_SOUNDS_DIRECTORY),
86	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY),
87	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_LIB_DIRECTORY),
88	KEYVALUE_PAIR(B_COMMON_NONPACKAGED_HEADERS_DIRECTORY),
89
90	// User directories
91	KEYVALUE_PAIR(B_USER_DIRECTORY),
92	KEYVALUE_PAIR(B_USER_CONFIG_DIRECTORY),
93	KEYVALUE_PAIR(B_USER_ADDONS_DIRECTORY),
94	KEYVALUE_PAIR(B_USER_BOOT_DIRECTORY),
95	KEYVALUE_PAIR(B_USER_FONTS_DIRECTORY),
96	KEYVALUE_PAIR(B_USER_LIB_DIRECTORY),
97	KEYVALUE_PAIR(B_USER_SETTINGS_DIRECTORY),
98	KEYVALUE_PAIR(B_USER_DESKBAR_DIRECTORY),
99	KEYVALUE_PAIR(B_USER_PRINTERS_DIRECTORY),
100	KEYVALUE_PAIR(B_USER_TRANSLATORS_DIRECTORY),
101	KEYVALUE_PAIR(B_USER_MEDIA_NODES_DIRECTORY),
102	KEYVALUE_PAIR(B_USER_SOUNDS_DIRECTORY),
103	KEYVALUE_PAIR(B_USER_DATA_DIRECTORY),
104	KEYVALUE_PAIR(B_USER_CACHE_DIRECTORY),
105	KEYVALUE_PAIR(B_USER_PACKAGES_DIRECTORY),
106	KEYVALUE_PAIR(B_USER_HEADERS_DIRECTORY),
107	KEYVALUE_PAIR(B_USER_NONPACKAGED_DIRECTORY),
108	KEYVALUE_PAIR(B_USER_NONPACKAGED_ADDONS_DIRECTORY),
109	KEYVALUE_PAIR(B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY),
110	KEYVALUE_PAIR(B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY),
111	KEYVALUE_PAIR(B_USER_NONPACKAGED_BIN_DIRECTORY),
112	KEYVALUE_PAIR(B_USER_NONPACKAGED_DATA_DIRECTORY),
113	KEYVALUE_PAIR(B_USER_NONPACKAGED_FONTS_DIRECTORY),
114	KEYVALUE_PAIR(B_USER_NONPACKAGED_SOUNDS_DIRECTORY),
115	KEYVALUE_PAIR(B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY),
116	KEYVALUE_PAIR(B_USER_NONPACKAGED_LIB_DIRECTORY),
117	KEYVALUE_PAIR(B_USER_NONPACKAGED_HEADERS_DIRECTORY),
118
119	// Legacy system directories
120	KEYVALUE_PAIR(B_BEOS_DIRECTORY),
121	KEYVALUE_PAIR(B_BEOS_SYSTEM_DIRECTORY),
122	KEYVALUE_PAIR(B_BEOS_ADDONS_DIRECTORY),
123	KEYVALUE_PAIR(B_BEOS_BOOT_DIRECTORY),
124	KEYVALUE_PAIR(B_BEOS_FONTS_DIRECTORY),
125	KEYVALUE_PAIR(B_BEOS_LIB_DIRECTORY),
126	KEYVALUE_PAIR(B_BEOS_SERVERS_DIRECTORY),
127	KEYVALUE_PAIR(B_BEOS_APPS_DIRECTORY),
128	KEYVALUE_PAIR(B_BEOS_BIN_DIRECTORY),
129	KEYVALUE_PAIR(B_BEOS_ETC_DIRECTORY),
130	KEYVALUE_PAIR(B_BEOS_DOCUMENTATION_DIRECTORY),
131	KEYVALUE_PAIR(B_BEOS_PREFERENCES_DIRECTORY),
132	KEYVALUE_PAIR(B_BEOS_TRANSLATORS_DIRECTORY),
133	KEYVALUE_PAIR(B_BEOS_MEDIA_NODES_DIRECTORY),
134	KEYVALUE_PAIR(B_BEOS_SOUNDS_DIRECTORY),
135	KEYVALUE_PAIR(B_BEOS_DATA_DIRECTORY),
136
137	{NULL, B_USER_DESKBAR_DIRECTORY}
138};
139
140
141static void
142listDirectoryWhich(void)
143{
144	int i;
145
146	for (i = 0; directoryTypes[i].key; i++) {
147		printf("%s\n", directoryTypes[i].key);
148	}
149}
150
151
152static bool
153retrieveDirValue(directoryType *list, const char *key,
154	directory_which *valueOut)
155{
156	unsigned i = 0;
157
158	while (list[i].key != NULL) {
159		if (strcmp(list[i].key, key) == 0) {
160			*valueOut = list[i].value;
161			return true;
162		}
163
164		i++;
165	}
166
167	return false;
168}
169
170
171static void
172usageMsg()
173{
174	printf("usage:  /bin/finddir -l | [ -v volume ] directory_which\n");
175	printf("\t-l\t    list valid which constants to use\n");
176	printf("\t-v <file>   use the specified volume for directory\n");
177	printf("\t\t    constants that are volume-specific.\n");
178	printf("\t\t    <file> can be any file on that volume.\n");
179	printf("\t\t    defaults to the boot volume.\n");
180	printf(" For a description of recognized directory_which constants,\n");
181	printf(" see the find_directory(...) documentation in the Be Book.\n");
182}
183
184
185int
186main(int argc, char *argv[])
187{
188	int directoryArgNr;
189	int status;
190	dev_t volume;
191	directory_which dirType;
192	int returnCode;
193
194	status = NO_ERRORS;
195	directoryArgNr = 1;
196	returnCode = 0;
197
198	dirType = B_BEOS_DIRECTORY; /* so that it compiles */
199
200	/* By default use boot volume*/
201	volume = dev_for_path("/boot");
202
203	if (argc <= 1) {
204		status = ARGUMENT_MISSING;
205	} else {
206		if (strcmp(argv[1], "-l") == 0 ) {
207			listDirectoryWhich();
208			return 0;
209		}
210		if (strcmp(argv[1], "-v") == 0 ) {
211			if (argc >= 3) {
212				dev_t temp_volume;
213				/* get volume from second arg */
214				temp_volume = dev_for_path(argv[2]);
215
216				/* Keep default value in case of error */
217				if (temp_volume >= 0)
218					volume = temp_volume;
219
220				/* two arguments were used for volume */
221				directoryArgNr+=2;
222			} else {
223				/* set status to argument missing */
224				status = ARGUMENT_MISSING;
225			}
226		}
227	}
228
229	if (status == NO_ERRORS && argc > directoryArgNr) {
230		/* get directory constant from next argument */
231
232		if (!retrieveDirValue(directoryTypes, argv[directoryArgNr], &dirType))
233			status = WRONG_DIR_TYPE;
234	} else {
235		status = ARGUMENT_MISSING;
236	}
237
238	/* Do the actual directoy finding */
239
240	if (status == NO_ERRORS) {
241		/* Question: would B_PATH_NAME_LENGTH alone have been enough? */
242		char buffer[B_PATH_NAME_LENGTH+B_FILE_NAME_LENGTH];
243		status_t result = find_directory (dirType, volume, false, buffer,
244			sizeof(buffer));
245		if (result == B_OK) {
246			printf("%s\n", buffer);
247		} else {
248			/* else what? */
249			/* this can not happen! */
250			fprintf(stderr, "Serious internal error; contact support\n");
251		}
252	}
253
254	/* Error messages and return code setting */
255
256	if (status == WRONG_DIR_TYPE) {
257		fprintf(stderr, "%s: unrecognized directory_which constant \'%s\'\n", argv[0],
258			argv[directoryArgNr]);
259		returnCode = 252;
260	}
261
262	if (status == ARGUMENT_MISSING) {
263		usageMsg();
264		returnCode = 255;
265	}
266
267	return returnCode;
268}
269
270