Whamcloud - gitweb
tests: move inode and its interior extent tree block
[tools/e2fsprogs.git] / misc / blkid.c
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 "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #ifdef HAVE_TERMIOS_H
18 #include <termios.h>
19 #endif
20 #ifdef HAVE_TERMIO_H
21 #include <termio.h>
22 #endif
23 #ifdef HAVE_SYS_IOCTL_H
24 #include <sys/ioctl.h>
25 #endif
26 #ifdef HAVE_GETOPT_H
27 #include <getopt.h>
28 #else
29 extern int getopt(int argc, char * const argv[], const char *optstring);
30 extern char *optarg;
31 extern int optind;
32 #endif
33
34 #define OUTPUT_VALUE_ONLY       0x0001
35 #define OUTPUT_DEVICE_ONLY      0x0002
36 #define OUTPUT_PRETTY_LIST      0x0004
37
38 #include "ext2fs/ext2fs.h"
39 #include "blkid/blkid.h"
40
41 static const char *progname = "blkid";
42
43 static void print_version(FILE *out)
44 {
45         fprintf(out, "%s %s (%s)\n", progname, BLKID_VERSION, BLKID_DATE);
46 }
47
48 static void usage(int error)
49 {
50         FILE *out = error ? stderr : stdout;
51
52         print_version(out);
53         fprintf(out,
54                 "usage:\t%s [-c <file>] [-ghlLv] [-o format] "
55                 "[-s <tag>] [-t <token>]\n    [-w <file>] [dev ...]\n"
56                 "\t-c\tcache file (default: /etc/blkid.tab, /dev/null = none)\n"
57                 "\t-h\tprint this usage message and exit\n"
58                 "\t-g\tgarbage collect the blkid cache\n"
59                 "\t-s\tshow specified tag(s) (default show all tags)\n"
60                 "\t-t\tfind device with a specific token (NAME=value pair)\n"
61                 "\t-l\tlookup the the first device with arguments specified by -t\n"
62                 "\t-v\tprint version and exit\n"
63                 "\t-w\twrite cache to different file (/dev/null = no write)\n"
64                 "\tdev\tspecify device(s) to probe (default: all devices)\n",
65                 progname);
66         exit(error);
67 }
68
69 /*
70  * This function does "safe" printing.  It will convert non-printable
71  * ASCII characters using '^' and M- notation.
72  */
73 static void safe_print(const char *cp, int len)
74 {
75         unsigned char   ch;
76
77         if (len < 0)
78                 len = strlen(cp);
79
80         while (len--) {
81                 ch = *cp++;
82                 if (ch > 128) {
83                         fputs("M-", stdout);
84                         ch -= 128;
85                 }
86                 if ((ch < 32) || (ch == 0x7f)) {
87                         fputc('^', stdout);
88                         ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
89                 }
90                 if (ch != '"') {
91                         fputc(ch, stdout);
92                 }
93         }
94 }
95
96 static int get_terminal_width(void)
97 {
98 #ifdef TIOCGSIZE
99         struct ttysize  t_win;
100 #endif
101 #ifdef TIOCGWINSZ
102         struct winsize  w_win;
103 #endif
104         const char      *cp;
105         int width = 80;
106
107 #ifdef TIOCGSIZE
108         if (ioctl (0, TIOCGSIZE, &t_win) == 0) {
109                 width = t_win.ts_cols;
110                 goto got_it;
111         }
112 #endif
113 #ifdef TIOCGWINSZ
114         if (ioctl (0, TIOCGWINSZ, &w_win) == 0) {
115                 width = w_win.ws_col;
116                 goto got_it;
117         }
118 #endif
119         cp = getenv("COLUMNS");
120         if (cp)
121                 width = atoi(cp);
122 got_it:
123         if (width > 4096)
124                 return 4096;    /* sanity check */
125         return width;
126 }
127
128 static int pretty_print_word(const char *str, int max_len,
129                              int left_len, int overflow_nl)
130 {
131         int len = strlen(str) + left_len;
132         int ret = 0;
133
134         fputs(str, stdout);
135         if (overflow_nl && len > max_len) {
136                 fputc('\n', stdout);
137                 len = 0;
138         } else if (len > max_len)
139                 ret = len - max_len;
140         do {
141                 fputc(' ', stdout);
142         } while (len++ < max_len);
143         return ret;
144 }
145
146 static void pretty_print_line(const char *device, const char *fs_type,
147                               const char *label, const char *mtpt,
148                               const char *uuid)
149 {
150         static int device_len = 10, fs_type_len = 7;
151         static int label_len = 8, mtpt_len = 14;
152         static int term_width = -1;
153         int len, w;
154
155         if (term_width < 0) {
156                 term_width = get_terminal_width();
157
158                 if (term_width > 80) {
159                         term_width -= 80;
160                         w = term_width / 10;
161                         if (w > 8)
162                                 w = 8;
163                         term_width -= 2*w;
164                         label_len += w;
165                         fs_type_len += w;
166                         w = term_width/2;
167                         device_len += w;
168                         mtpt_len +=w;
169                 }
170         }
171
172         len = pretty_print_word(device, device_len, 0, 1);
173         len = pretty_print_word(fs_type, fs_type_len, len, 0);
174         len = pretty_print_word(label, label_len, len, 0);
175         len = pretty_print_word(mtpt, mtpt_len, len, 0);
176         fputs(uuid, stdout);
177         fputc('\n', stdout);
178 }
179
180 static void pretty_print_dev(blkid_dev dev)
181 {
182         blkid_tag_iterate       iter;
183         const char              *type, *value, *devname;
184         const char              *uuid = "", *fs_type = "", *label = "";
185         int                     len, mount_flags;
186         char                    mtpt[80];
187         errcode_t               retval;
188
189         if (dev == NULL) {
190                 pretty_print_line("device", "fs_type", "label",
191                                   "mount point", "UUID");
192                 for (len=get_terminal_width()-1; len > 0; len--)
193                         fputc('-', stdout);
194                 fputc('\n', stdout);
195                 return;
196         }
197
198         devname = blkid_dev_devname(dev);
199         if (access(devname, F_OK))
200                 return;
201
202         /* Get the uuid, label, type */
203         iter = blkid_tag_iterate_begin(dev);
204         while (blkid_tag_next(iter, &type, &value) == 0) {
205                 if (!strcmp(type, "UUID"))
206                         uuid = value;
207                 if (!strcmp(type, "TYPE"))
208                         fs_type = value;
209                 if (!strcmp(type, "LABEL"))
210                         label = value;
211         }
212         blkid_tag_iterate_end(iter);
213
214         /* Get the mount point */
215         mtpt[0] = 0;
216         retval = ext2fs_check_mount_point(devname, &mount_flags,
217                                           mtpt, sizeof(mtpt));
218         if (retval == 0) {
219                 if (mount_flags & EXT2_MF_MOUNTED) {
220                         if (!mtpt[0])
221                                 strcpy(mtpt, "(mounted, mtpt unknown)");
222                 } else if (mount_flags & EXT2_MF_BUSY)
223                         strcpy(mtpt, "(in use)");
224                 else
225                         strcpy(mtpt, "(not mounted)");
226         }
227
228         pretty_print_line(devname, fs_type, label, mtpt, uuid);
229 }
230
231 static void print_tags(blkid_dev dev, char *show[], int numtag, int output)
232 {
233         blkid_tag_iterate       iter;
234         const char              *type, *value;
235         int                     i, first = 1;
236
237         if (!dev)
238                 return;
239
240         if (output & OUTPUT_PRETTY_LIST) {
241                 pretty_print_dev(dev);
242                 return;
243         }
244
245         if (output & OUTPUT_DEVICE_ONLY) {
246                 printf("%s\n", blkid_dev_devname(dev));
247                 return;
248         }
249
250         iter = blkid_tag_iterate_begin(dev);
251         while (blkid_tag_next(iter, &type, &value) == 0) {
252                 if (numtag && show) {
253                         for (i=0; i < numtag; i++)
254                                 if (!strcmp(type, show[i]))
255                                         break;
256                         if (i >= numtag)
257                                 continue;
258                 }
259                 if (output & OUTPUT_VALUE_ONLY) {
260                         fputs(value, stdout);
261                         fputc('\n', stdout);
262                 } else {
263                         if (first) {
264                                 printf("%s: ", blkid_dev_devname(dev));
265                                 first = 0;
266                         }
267                         fputs(type, stdout);
268                         fputs("=\"", stdout);
269                         safe_print(value, -1);
270                         fputs("\" ", stdout);
271                 }
272         }
273         blkid_tag_iterate_end(iter);
274
275         if (!first && !(output & OUTPUT_VALUE_ONLY))
276                 printf("\n");
277 }
278
279 int main(int argc, char **argv)
280 {
281         blkid_cache cache = NULL;
282         char *devices[128] = { NULL, };
283         char *show[128] = { NULL, };
284         char *search_type = NULL, *search_value = NULL;
285         char *read = NULL;
286         char *write = NULL;
287         unsigned int numdev = 0, numtag = 0;
288         int version = 0;
289         int err = 4;
290         unsigned int i;
291         int output_format = 0;
292         int lookup = 0, gc = 0;
293         int c;
294
295         while ((c = getopt (argc, argv, "c:f:ghlLo:s:t:w:v")) != EOF)
296                 switch (c) {
297                 case 'c':
298                         read = optarg;
299                         if (!write)
300                                 write = read;
301                         break;
302                 case 'l':
303                         lookup++;
304                         break;
305                 case 'L':
306                         output_format = OUTPUT_PRETTY_LIST;
307                         break;
308                 case 'g':
309                         gc = 1;
310                         break;
311                 case 'o':
312                         if (!strcmp(optarg, "value"))
313                                 output_format = OUTPUT_VALUE_ONLY;
314                         else if (!strcmp(optarg, "device"))
315                                 output_format = OUTPUT_DEVICE_ONLY;
316                         else if (!strcmp(optarg, "list"))
317                                 output_format = OUTPUT_PRETTY_LIST;
318                         else if (!strcmp(optarg, "full"))
319                                 output_format = 0;
320                         else {
321                                 fprintf(stderr, "Invalid output format %s. "
322                                         "Choose from value,\n\t"
323                                         "device, list, or full\n", optarg);
324                                 exit(1);
325                         }
326                         break;
327                 case 's':
328                         if (numtag >= sizeof(show) / sizeof(*show)) {
329                                 fprintf(stderr, "Too many tags specified\n");
330                                 usage(err);
331                         }
332                         show[numtag++] = optarg;
333                         break;
334                 case 't':
335                         if (search_type) {
336                                 fprintf(stderr, "Can only search for "
337                                                 "one NAME=value pair\n");
338                                 usage(err);
339                         }
340                         if (blkid_parse_tag_string(optarg,
341                                                    &search_type,
342                                                    &search_value)) {
343                                 fprintf(stderr, "-t needs NAME=value pair\n");
344                                 usage(err);
345                         }
346                         break;
347                 case 'v':
348                         version = 1;
349                         break;
350                 case 'w':
351                         write = optarg;
352                         break;
353                 case 'h':
354                         err = 0;
355                         /* fallthrough */
356                 default:
357                         usage(err);
358                 }
359
360         while (optind < argc)
361                 devices[numdev++] = argv[optind++];
362
363         if (version) {
364                 print_version(stdout);
365                 goto exit;
366         }
367
368         if (blkid_get_cache(&cache, read) < 0)
369                 goto exit;
370
371         err = 2;
372         if (gc) {
373                 blkid_gc_cache(cache);
374                 goto exit;
375         }
376         if (output_format & OUTPUT_PRETTY_LIST)
377                 pretty_print_dev(NULL);
378
379         if (lookup) {
380                 blkid_dev dev;
381
382                 if (!search_type) {
383                         fprintf(stderr, "The lookup option requires a "
384                                 "search type specified using -t\n");
385                         exit(1);
386                 }
387                 /* Load any additional devices not in the cache */
388                 for (i = 0; i < numdev; i++)
389                         blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL);
390
391                 if ((dev = blkid_find_dev_with_tag(cache, search_type,
392                                                    search_value))) {
393                         print_tags(dev, show, numtag, output_format);
394                         err = 0;
395                 }
396         /* If we didn't specify a single device, show all available devices */
397         } else if (!numdev) {
398                 blkid_dev_iterate       iter;
399                 blkid_dev               dev;
400
401                 blkid_probe_all(cache);
402
403                 iter = blkid_dev_iterate_begin(cache);
404                 blkid_dev_set_search(iter, search_type, search_value);
405                 while (blkid_dev_next(iter, &dev) == 0) {
406                         dev = blkid_verify(cache, dev);
407                         if (!dev)
408                                 continue;
409                         print_tags(dev, show, numtag, output_format);
410                         err = 0;
411                 }
412                 blkid_dev_iterate_end(iter);
413         /* Add all specified devices to cache (optionally display tags) */
414         } else for (i = 0; i < numdev; i++) {
415                 blkid_dev dev = blkid_get_dev(cache, devices[i],
416                                                   BLKID_DEV_NORMAL);
417
418                 if (dev) {
419                         if (search_type &&
420                             !blkid_dev_has_tag(dev, search_type,
421                                                search_value))
422                                 continue;
423                         print_tags(dev, show, numtag, output_format);
424                         err = 0;
425                 }
426         }
427
428 exit:
429         free(search_type);
430         free(search_value);
431         blkid_put_cache(cache);
432         return err;
433 }