1/*
2 * Copyright 2003-2006 Haiku Inc.
3 * Distributed under the terms of the MIT license
4 *
5 * Authors:
6 *		Scott Dellinger (dellinsd@myrealbox.com)
7 *		J��r��me Duval
8 */
9
10
11#include <fs_info.h>
12#include <fs_index.h>
13#include <TypeConstants.h>
14
15#include <errno.h>
16#include <getopt.h>
17#include <glob.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22
23extern const char *__progname;
24const char *kProgramName = __progname;
25
26dev_t gCurrentDevice;
27
28// The following enum and #define are copied from gnu/sys2.h, because it
29// didn't want to compile when including that directly.  Since that file
30// is marked as being temporary and getting migrated into system.h,
31// assume these'll go away soon.
32
33/* These enum values cannot possibly conflict with the option values
34   ordinarily used by commands, including CHAR_MAX + 1, etc.  Avoid
35   CHAR_MIN - 1, as it may equal -1, the getopt end-of-options value.  */
36enum {
37  GETOPT_HELP_CHAR = (CHAR_MIN - 2),
38  GETOPT_VERSION_CHAR = (CHAR_MIN - 3)
39};
40
41static struct option const longopts[] = {
42	{"volume", required_argument, 0, 'd'},
43	{"type", required_argument, 0, 't'},
44	{"pattern", no_argument, 0, 'p'},
45	{"verbose", no_argument, 0, 'v'},
46	{"help", no_argument, 0, GETOPT_HELP_CHAR},
47	{0, 0, 0, 0}
48};
49
50
51void
52usage(int status)
53{
54	fprintf (stderr,
55		"Usage: %s [OPTION]... INDEX_NAME\n"
56		"\n"
57		"Removes the index named INDEX_NAME from a disk volume.  Once this has been\n"
58		"done, it will no longer be possible to use the query system to search for\n"
59		"files with the INDEX_NAME attribute.\n"
60		"\n"
61		"  -d, --volume=PATH	a path on the volume from which the index will be\n"
62		"                         removed\n"
63		"  -h, --help		display this help and exit\n"
64		"  -p, --pattern		INDEX_NAME is a pattern\n"
65		"  -v, --verbose		print information about the index being removed\n"
66		"\n"
67		"INDEX_NAME is the name of a file attribute.\n"
68		"\n"
69		"If no volume is specified, the volume of the current directory is assumed.\n",
70		kProgramName);
71
72	exit(status);
73}
74
75
76const char*
77lookup_index_type(uint32 device_type)
78{
79	switch (device_type) {
80		case B_DOUBLE_TYPE:
81		  return "double";
82		case B_FLOAT_TYPE:
83		  return "float";
84		case B_INT64_TYPE:
85		  return "llong";
86		case B_INT32_TYPE:
87		  return "int";
88		case B_STRING_TYPE:
89		  return "string";
90
91		default:
92		  return "unknown";
93	}
94}
95
96
97int
98remove_index(dev_t device, const char* indexName, bool verbose)
99{
100	if (verbose) {
101		// Get the index type
102		index_info info;
103		status_t status = fs_stat_index(device, indexName, &info);
104		if (status != B_OK) {
105			fprintf(stderr, "%s: Can't get type of index %s: %s\n",
106				kProgramName, indexName, strerror(errno));
107			return -1;
108		}
109
110		fprintf(stdout, "Removing index \"%s\" of type %s.\n",
111			indexName, lookup_index_type(info.type));
112	}
113
114	if (fs_remove_index(device, indexName) != 0) {
115		fprintf(stderr, "%s: Cannot remove index %s: %s\n", kProgramName, indexName, strerror(errno));
116		return -1;
117	}
118
119	return 0;
120}
121
122
123void *
124open_index_dir(const char* /*path*/)
125{
126	return fs_open_index_dir(gCurrentDevice);
127}
128
129
130int
131stat_index(const char* /*index*/, struct stat* stat)
132{
133	memset(stat, 0, sizeof(struct stat));
134	stat->st_mode = S_IFREG;
135	return 0;
136}
137
138
139int
140remove_indices(dev_t device, const char* indexPattern, bool verbose)
141{
142	glob_t glob;
143	memset(&glob, 0, sizeof(glob_t));
144
145	glob.gl_closedir = (void (*)(void *))fs_close_index_dir;
146	glob.gl_readdir = (dirent *(*)(void *))fs_read_index_dir;
147	glob.gl_opendir = open_index_dir;
148	glob.gl_lstat = stat_index;
149	glob.gl_stat = stat_index;
150
151	// for open_attr_dir():
152	gCurrentDevice = device;
153
154	int result = ::glob(indexPattern, GLOB_ALTDIRFUNC, NULL, &glob);
155	if (result < 0) {
156		errno = B_BAD_VALUE;
157		return -1;
158	}
159
160	bool error = false;
161
162	for (int i = 0; i < glob.gl_pathc; i++) {
163		if (remove_index(device, glob.gl_pathv[i], verbose) != 0)
164			error = true;
165	}
166
167	return error ? -1 : 0;
168}
169
170
171int
172main(int argc, char **argv)
173{
174	bool isPattern = false;
175	bool verbose = false;
176	dev_t device = 0;
177	char *indexName = NULL;
178	char *path = NULL;
179
180	int c;
181	while ((c = getopt_long(argc, argv, "d:ht:pv", longopts, NULL)) != -1) {
182		switch (c) {
183			case 0:
184				break;
185			case 'd':
186				path = optarg;
187			  	break;
188			case GETOPT_HELP_CHAR:
189				usage(0);
190				break;
191			case 'p':
192				isPattern = true;
193				break;
194			case 'v':
195				verbose = true;
196				break;
197			default:
198	  			usage(1);
199		  		break;
200		}
201	}
202
203	// Remove the index from the volume of the current
204	// directory if no volume was specified.
205	if (path == NULL)
206		path = ".";
207
208	device = dev_for_path(path);
209	if (device < 0) {
210		fprintf(stderr, "%s: can't get information about volume %s\n", kProgramName, path);
211		return 1;
212	}
213
214	if (argc - optind == 1) {
215		// last argument
216		indexName = argv[optind];
217	} else
218		usage(1);
219
220	int result;
221	if (isPattern)
222		result = remove_indices(device, indexName, verbose);
223	else
224		result = remove_index(device, indexName, verbose);
225
226	return result == 0 ? 0 : 1;
227}
228