xref: /haiku/src/bin/query.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
1 /*
2  * Copyright 2005, Haiku Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *	Ficus Kirkpatrick (ficus@ior.com)
7  *	Jérôme Duval
8  *	Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 /* A shell utility for somewhat emulating the Tracker's "Find By Formula"
12  * functionality.
13  */
14 
15 
16 #include <Path.h>
17 #include <Query.h>
18 #include <Entry.h>
19 #include <Volume.h>
20 #include <VolumeRoster.h>
21 #include <String.h>
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 
28 
29 extern const char *__progname;
30 static const char *kProgramName = __progname;
31 
32 // Option variables.
33 static bool sAllVolumes = false;		// Query all volumes?
34 static bool sEscapeMetaChars = true;	// Escape metacharacters?
35 static bool sFilesOnly = false;			// Show only files?
36 
37 
38 void
39 usage(void)
40 {
41 	printf("usage: %s [ -ef ] [ -a || -v <path-to-volume> ] expression\n"
42 		"  -e\t\tdon't escape meta-characters\n"
43 		"  -f\t\tshow only files (ie. no directories or symbolic links)\n"
44 		"  -a\t\tperform the query on all volumes\n"
45 		"  -v <file>\tperform the query on just one volume; <file> can be any\n"
46 		"\t\tfile on that volume. Defaults to the current volume.\n"
47 		"  Hint: '%s name=foo' will find files named \"foo\"\n",
48 		kProgramName, kProgramName);
49 	exit(0);
50 }
51 
52 
53 void
54 perform_query(BVolume &volume, const char *predicate)
55 {
56 	BQuery query;
57 
58 	// Set up the volume and predicate for the query.
59 	query.SetVolume(&volume);
60 	query.SetPredicate(predicate);
61 
62 	status_t status = query.Fetch();
63 	if (status == B_BAD_VALUE) {
64 		// the "name=" part may be omitted in our arguments
65 		BString string = "name=";
66 		string << predicate;
67 
68 		query.SetPredicate(string.String());
69 		status = query.Fetch();
70 	}
71 	if (status != B_OK) {
72 		fprintf(stderr, "%s: bad query expression\n", kProgramName);
73 		return;
74 	}
75 
76 	BEntry entry;
77 	BPath path;
78 	while (query.GetNextEntry(&entry) == B_OK) {
79 		if (sFilesOnly && !entry.IsFile())
80 			continue;
81 
82 		if (entry.GetPath(&path) < B_OK) {
83 			fprintf(stderr, "%s: could not get path for entry\n", kProgramName);
84 			continue;
85 		}
86 
87 		printf("%s\n", sEscapeMetaChars ?
88 			BString().CharacterEscape(path.Path(), " ()?*&\"'[]^\\~|;!<>*$\t", '\\').String()
89 			: path.Path());
90 	}
91 }
92 
93 
94 int
95 main(int argc, char **argv)
96 {
97 	// Make sure we have the minimum number of arguments.
98 	if (argc < 2)
99 		usage();
100 
101 	// Which volume do we make the query on?
102 	// Default to the current volume.
103 	char volumePath[B_FILE_NAME_LENGTH];
104 	strcpy(volumePath, ".");
105 
106 	// Parse command-line arguments.
107 	int opt;
108 	while ((opt = getopt(argc, argv, "efav:")) != -1) {
109 		switch(opt) {
110 			case 'e':
111 				sEscapeMetaChars = false;
112 				break;
113 			case 'f':
114 				sFilesOnly = true;
115 				break;
116 			case 'a':
117 				sAllVolumes = true;
118 				break;
119 			case 'v':
120 				strncpy(volumePath, optarg, B_FILE_NAME_LENGTH);
121 				break;
122 
123 			default:
124 				usage();
125 				break;
126 		}
127 	}
128 
129 	BVolume volume;
130 
131 	if (!sAllVolumes) {
132 		// Find the volume that the query should be performed on,
133 		// and set the query to it.
134 		BEntry entry(volumePath);
135 		if (entry.InitCheck() != B_OK) {
136 			fprintf(stderr, "%s: \"%s\" is not a valid file\n", kProgramName, volumePath);
137 			exit(1);
138 		}
139 
140 		status_t status = entry.GetVolume(&volume);
141 		if (status != B_OK) {
142 			fprintf(stderr, "%s: could not get volume: %s\n", kProgramName, strerror(status));
143 			exit(1);
144 		}
145 
146 		if (!volume.KnowsQuery())
147 			fprintf(stderr, "%s: volume containing %s is not query-enabled\n", kProgramName, volumePath);
148 		else
149 			perform_query(volume, argv[optind]);
150 	} else {
151 		// Okay, we want to query all the disks -- so iterate over
152 		// them, one by one, running the query.
153 		BVolumeRoster volumeRoster;
154 		while (volumeRoster.GetNextVolume(&volume) == B_OK) {
155 			// We don't print errors here -- this will catch /pipe and
156 			// other filesystems we don't care about.
157 			if (volume.KnowsQuery())
158 				perform_query(volume, argv[optind]);
159 		}
160 	}
161 
162 	return 0;
163 }
164