1/*
2 * blkid.c - User command-line interface for libblkid
3 *
4 * Copyright (C) 2001 Andreas Dilger
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#ifdef HAVE_GETOPT_H
16#include <getopt.h>
17#else
18extern int getopt(int argc, char * const argv[], const char *optstring);
19extern char *optarg;
20extern int optind;
21#endif
22
23#define OUTPUT_VALUE_ONLY	0x0001
24#define OUTPUT_DEVICE_ONLY	0x0002
25
26#include "blkid/blkid.h"
27
28const char *progname = "blkid";
29
30static void print_version(FILE *out)
31{
32	fprintf(out, "%s %s (%s)\n", progname, BLKID_VERSION, BLKID_DATE);
33}
34
35static void usage(int error)
36{
37	FILE *out = error ? stderr : stdout;
38
39	print_version(out);
40	fprintf(out,
41		"usage:\t%s [-c <file>] [-ghl] [-o format] "
42		"[-s <tag>] [-t <token>]\n    [-v] [-w <file>] [dev ...]\n"
43		"\t-c\tcache file (default: /etc/blkid.tab, /dev/null = none)\n"
44		"\t-h\tprint this usage message and exit\n"
45		"\t-g\tgarbage collect the blkid cache\n"
46		"\t-s\tshow specified tag(s) (default show all tags)\n"
47		"\t-t\tfind device with a specific token (NAME=value pair)\n"
48		"\t-l\tlookup the the first device with arguments specified by -t\n"
49		"\t-v\tprint version and exit\n"
50		"\t-w\twrite cache to different file (/dev/null = no write)\n"
51		"\tdev\tspecify device(s) to probe (default: all devices)\n",
52		progname);
53	exit(error);
54}
55
56/*
57 * This function does "safe" printing.  It will convert non-printable
58 * ASCII characters using '^' and M- notation.
59 */
60static void safe_print(const char *cp, int len)
61{
62	unsigned char	ch;
63
64	if (len < 0)
65		len = strlen(cp);
66
67	while (len--) {
68		ch = *cp++;
69		if (ch > 128) {
70			fputs("M-", stdout);
71			ch -= 128;
72		}
73		if ((ch < 32) || (ch == 0x7f)) {
74			fputc('^', stdout);
75			ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
76		}
77		fputc(ch, stdout);
78	}
79}
80
81static void print_tags(blkid_dev dev, char *show[], int numtag, int output)
82{
83	blkid_tag_iterate	iter;
84	const char		*type, *value;
85	int 			i, first = 1;
86
87	if (!dev)
88		return;
89
90	if (output & OUTPUT_DEVICE_ONLY) {
91		printf("%s\n", blkid_dev_devname(dev));
92		return;
93	}
94
95	iter = blkid_tag_iterate_begin(dev);
96	while (blkid_tag_next(iter, &type, &value) == 0) {
97		if (numtag && show) {
98			for (i=0; i < numtag; i++)
99				if (!strcmp(type, show[i]))
100					break;
101			if (i >= numtag)
102				continue;
103		}
104		if (output & OUTPUT_VALUE_ONLY) {
105			fputs(value, stdout);
106			fputc('\n', stdout);
107		} else {
108			if (first) {
109				printf("%s: ", blkid_dev_devname(dev));
110				first = 0;
111			}
112			fputs(type, stdout);
113			fputs("=\"", stdout);
114			safe_print(value, -1);
115			fputs("\" ", stdout);
116		}
117	}
118	blkid_tag_iterate_end(iter);
119
120	if (!first && !(output & OUTPUT_VALUE_ONLY))
121		printf("\n");
122}
123
124int main(int argc, char **argv)
125{
126	blkid_cache cache = NULL;
127	char *devices[128] = { NULL, };
128	char *show[128] = { NULL, };
129	char *search_type = NULL, *search_value = NULL;
130	char *read = NULL;
131	char *write = NULL;
132	unsigned int numdev = 0, numtag = 0;
133	int version = 0;
134	int err = 4;
135	unsigned int i;
136	int output_format = 0;
137	int lookup = 0, gc = 0;
138	int c;
139
140	while ((c = getopt (argc, argv, "c:f:ghlo:s:t:w:v")) != EOF)
141		switch (c) {
142		case 'c':
143			if (optarg && !*optarg)
144				read = NULL;
145			else
146				read = optarg;
147			if (!write)
148				write = read;
149			break;
150		case 'l':
151			lookup++;
152			break;
153		case 'g':
154			gc = 1;
155			break;
156		case 'o':
157			if (!strcmp(optarg, "value"))
158				output_format = OUTPUT_VALUE_ONLY;
159			else if (!strcmp(optarg, "device"))
160				output_format = OUTPUT_DEVICE_ONLY;
161			else if (!strcmp(optarg, "full"))
162				output_format = 0;
163			else {
164				fprintf(stderr, "Invalid output format %s.  Chose from value, device, or full\n", optarg);
165				exit(1);
166			}
167			break;
168		case 's':
169			if (numtag >= sizeof(show) / sizeof(*show)) {
170				fprintf(stderr, "Too many tags specified\n");
171				usage(err);
172			}
173			show[numtag++] = optarg;
174			break;
175		case 't':
176			if (search_type) {
177				fprintf(stderr, "Can only search for "
178						"one NAME=value pair\n");
179				usage(err);
180			}
181			if (blkid_parse_tag_string(optarg,
182						   &search_type,
183						   &search_value)) {
184				fprintf(stderr, "-t needs NAME=value pair\n");
185				usage(err);
186			}
187			break;
188		case 'v':
189			version = 1;
190			break;
191		case 'w':
192			if (optarg && !*optarg)
193				write = NULL;
194			else
195				write = optarg;
196			break;
197		case 'h':
198			err = 0;
199		default:
200			usage(err);
201		}
202
203	while (optind < argc)
204		devices[numdev++] = argv[optind++];
205
206	if (version) {
207		print_version(stdout);
208		goto exit;
209	}
210
211	if (blkid_get_cache(&cache, read) < 0)
212		goto exit;
213
214	err = 2;
215	if (gc) {
216		blkid_gc_cache(cache);
217	} else if (lookup) {
218		blkid_dev dev;
219
220		if (!search_type) {
221			fprintf(stderr, "The lookup option requires a "
222				"search type specified using -t\n");
223			exit(1);
224		}
225		/* Load any additional devices not in the cache */
226		for (i = 0; i < numdev; i++)
227			blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL);
228
229		if ((dev = blkid_find_dev_with_tag(cache, search_type,
230						   search_value))) {
231			print_tags(dev, show, numtag, output_format);
232			err = 0;
233		}
234	/* If we didn't specify a single device, show all available devices */
235	} else if (!numdev) {
236		blkid_dev_iterate	iter;
237		blkid_dev		dev;
238
239		blkid_probe_all(cache);
240
241		iter = blkid_dev_iterate_begin(cache);
242		blkid_dev_set_search(iter, search_type, search_value);
243		while (blkid_dev_next(iter, &dev) == 0) {
244			dev = blkid_verify(cache, dev);
245			if (!dev)
246				continue;
247			print_tags(dev, show, numtag, output_format);
248			err = 0;
249		}
250		blkid_dev_iterate_end(iter);
251	/* Add all specified devices to cache (optionally display tags) */
252	} else for (i = 0; i < numdev; i++) {
253		blkid_dev dev = blkid_get_dev(cache, devices[i],
254						  BLKID_DEV_NORMAL);
255
256		if (dev) {
257			if (search_type &&
258			    !blkid_dev_has_tag(dev, search_type,
259					       search_value))
260				continue;
261			print_tags(dev, show, numtag, output_format);
262			err = 0;
263		}
264	}
265
266exit:
267	if (search_type)
268		free(search_type);
269	if (search_value)
270		free(search_value);
271	blkid_put_cache(cache);
272	return err;
273}
274