Upload Tizen:Base source
[framework/base/util-linux-ng.git] / misc-utils / 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 <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #ifdef HAVE_TERMIOS_H
20 #include <termios.h>
21 #endif
22 #ifdef HAVE_TERMIO_H
23 #include <termio.h>
24 #endif
25 #ifdef HAVE_SYS_IOCTL_H
26 #include <sys/ioctl.h>
27 #endif
28 #ifdef HAVE_GETOPT_H
29 #include <getopt.h>
30 #else
31 extern int getopt(int argc, char * const argv[], const char *optstring);
32 extern char *optarg;
33 extern int optind;
34 #endif
35
36 #define OUTPUT_VALUE_ONLY       0x0001
37 #define OUTPUT_DEVICE_ONLY      0x0002
38 #define OUTPUT_PRETTY_LIST      0x0004
39 #define OUTPUT_UDEV_LIST        0x0008
40
41 #include <blkid.h>
42
43 const char *progname = "blkid";
44
45 static void print_version(FILE *out)
46 {
47         fprintf(out, "%s from %s (libblkid %s, %s)\n",
48                 progname, PACKAGE_STRING, LIBBLKID_VERSION, LIBBLKID_DATE);
49 }
50
51 static void usage(int error)
52 {
53         FILE *out = error ? stderr : stdout;
54
55         print_version(out);
56         fprintf(out,
57                 "Usage:\n"
58                 "  %1$s -L <label> | -U <uuid>\n\n"
59                 "  %1$s [-c <file>] [-ghlLv] [-o format] [-s <tag>] \n"
60                 "        [-t <token>] [-w <file>] [dev ...]\n\n"
61                 "  %1$s -p [-O <offset>] [-S <size>] [-o format] <dev> [dev ...]\n\n"
62                 "Options:\n"
63                 "  -c <file>   cache file (default: /etc/blkid.tab, /dev/null = none)\n"
64                 "  -h          print this usage message and exit\n"
65                 "  -g          garbage collect the blkid cache\n"
66                 "  -o <format> output format; can be one of:\n"
67                 "              value, device, list, udev or full; (default: full)\n"
68                 "  -s <tag>    show specified tag(s) (default show all tags)\n"
69                 "  -t <token>  find device with a specific token (NAME=value pair)\n"
70                 "  -l          lookup the the first device with arguments specified by -t\n"
71                 "  -L <label>  convert LABEL to device name\n"
72                 "  -U <uuid>   convert UUID to device name\n"
73                 "  -v          print version and exit\n"
74                 "  -w <file>   write cache to different file (/dev/null = no write)\n"
75                 "  <dev>       specify device(s) to probe (default: all devices)\n\n"
76                 "Low-level probing options:\n"
77                 "  -p          switch to low-level mode (bypass cache)\n"
78                 "  -S <bytes>  overwrite device size\n"
79                 "  -O <bytes>  probe at the given offset\n"
80                 "  -u <list>   filter by \"usage\" (e.g. -u filesystem,raid)\n"
81                 "\n",
82                                 progname);
83
84         exit(error);
85 }
86
87 /*
88  * This function does "safe" printing.  It will convert non-printable
89  * ASCII characters using '^' and M- notation.
90  */
91 static void safe_print(const char *cp, int len)
92 {
93         unsigned char   ch;
94
95         if (len < 0)
96                 len = strlen(cp);
97
98         while (len--) {
99                 ch = *cp++;
100                 if (ch > 128) {
101                         fputs("M-", stdout);
102                         ch -= 128;
103                 }
104                 if ((ch < 32) || (ch == 0x7f)) {
105                         fputc('^', stdout);
106                         ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
107                 }
108                 fputc(ch, stdout);
109         }
110 }
111
112 static int get_terminal_width(void)
113 {
114 #ifdef TIOCGSIZE
115         struct ttysize  t_win;
116 #endif
117 #ifdef TIOCGWINSZ
118         struct winsize  w_win;
119 #endif
120         const char      *cp;
121
122 #ifdef TIOCGSIZE
123         if (ioctl (0, TIOCGSIZE, &t_win) == 0)
124                 return (t_win.ts_cols);
125 #endif
126 #ifdef TIOCGWINSZ
127         if (ioctl (0, TIOCGWINSZ, &w_win) == 0)
128                 return (w_win.ws_col);
129 #endif
130         cp = getenv("COLUMNS");
131         if (cp)
132                 return strtol(cp, NULL, 10);
133         return 80;
134 }
135
136 static int pretty_print_word(const char *str, int max_len,
137                              int left_len, int overflow_nl)
138 {
139         int len = strlen(str) + left_len;
140         int ret = 0;
141
142         fputs(str, stdout);
143         if (overflow_nl && len > max_len) {
144                 fputc('\n', stdout);
145                 len = 0;
146         } else if (len > max_len)
147                 ret = len - max_len;
148         do
149                 fputc(' ', stdout);
150         while (len++ < max_len);
151         return ret;
152 }
153
154 static void pretty_print_line(const char *device, const char *fs_type,
155                               const char *label, const char *mtpt,
156                               const char *uuid)
157 {
158         static int device_len = 10, fs_type_len = 7;
159         static int label_len = 8, mtpt_len = 14;
160         static int term_width = -1;
161         int len, w;
162
163         if (term_width < 0)
164                 term_width = get_terminal_width();
165
166         if (term_width > 80) {
167                 term_width -= 80;
168                 w = term_width / 10;
169                 if (w > 8)
170                         w = 8;
171                 term_width -= 2*w;
172                 label_len += w;
173                 fs_type_len += w;
174                 w = term_width/2;
175                 device_len += w;
176                 mtpt_len +=w;
177         }
178
179         len = pretty_print_word(device, device_len, 0, 1);
180         len = pretty_print_word(fs_type, fs_type_len, len, 0);
181         len = pretty_print_word(label, label_len, len, 0);
182         len = pretty_print_word(mtpt, mtpt_len, len, 0);
183         fputs(uuid, stdout);
184         fputc('\n', stdout);
185 }
186
187 static void pretty_print_dev(blkid_dev dev)
188 {
189         fprintf(stderr, "pretty print not implemented yet\n");
190
191 #ifdef NOT_IMPLEMENTED
192         blkid_tag_iterate       iter;
193         const char              *type, *value, *devname;
194         const char              *uuid = "", *fs_type = "", *label = "";
195         char                    *cp;
196         int                     len, mount_flags;
197         char                    mtpt[80];
198         errcode_t               retval;
199
200         if (dev == NULL) {
201                 pretty_print_line("device", "fs_type", "label",
202                                   "mount point", "UUID");
203                 for (len=get_terminal_width()-1; len > 0; len--)
204                         fputc('-', stdout);
205                 fputc('\n', stdout);
206                 return;
207         }
208
209         devname = blkid_dev_devname(dev);
210         if (access(devname, F_OK))
211                 return;
212
213         /* Get the uuid, label, type */
214         iter = blkid_tag_iterate_begin(dev);
215         while (blkid_tag_next(iter, &type, &value) == 0) {
216                 if (!strcmp(type, "UUID"))
217                         uuid = value;
218                 if (!strcmp(type, "TYPE"))
219                         fs_type = value;
220                 if (!strcmp(type, "LABEL"))
221                         label = value;
222         }
223         blkid_tag_iterate_end(iter);
224
225         /* Get the mount point */
226         mtpt[0] = 0;
227         retval = ext2fs_check_mount_point(devname, &mount_flags,
228                                           mtpt, sizeof(mtpt));
229         if (retval == 0) {
230                 if (mount_flags & EXT2_MF_MOUNTED) {
231                         if (!mtpt[0])
232                                 strcpy(mtpt, "(mounted, mtpt unknown)");
233                 } else if (mount_flags & EXT2_MF_BUSY)
234                         strcpy(mtpt, "(in use)");
235                 else
236                         strcpy(mtpt, "(not mounted)");
237         }
238
239         pretty_print_line(devname, fs_type, label, mtpt, uuid);
240 #endif
241 }
242
243 static void print_udev_format(const char *name, const char *value, size_t sz)
244 {
245         char enc[265], safe[256];
246
247         *safe = *enc = '\0';
248
249         if (!strcmp(name, "TYPE") || !strcmp(name, "VERSION")) {
250                 blkid_encode_string(value, enc, sizeof(enc));
251                 printf("ID_FS_%s=%s\n", name, enc);
252
253         } else if (!strcmp(name, "UUID") ||
254                  !strcmp(name, "LABEL") ||
255                  !strcmp(name, "UUID_SUB")) {
256
257                 blkid_safe_string(value, safe, sizeof(safe));
258                 printf("ID_FS_%s=%s\n", name, safe);
259
260                 blkid_encode_string(value, enc, sizeof(enc));
261                 printf("ID_FS_%s_ENC=%s\n", name, enc);
262         }
263         else
264                 printf("ID_FS_%s=%s\n", name, value);
265 }
266
267 static void print_value(int output, int num, const char *devname,
268                         const char *value, const char *name, size_t valsz)
269 {
270         if (output & OUTPUT_VALUE_ONLY) {
271                 fputs(value, stdout);
272                 fputc('\n', stdout);
273
274         } else if (output & OUTPUT_UDEV_LIST) {
275                 print_udev_format(name, value, valsz);
276
277         } else {
278                 if (num == 1 && devname)
279                         printf("%s: ", devname);
280                 fputs(name, stdout);
281                 fputs("=\"", stdout);
282                 safe_print(value, valsz);
283                 fputs("\" ", stdout);
284         }
285 }
286
287 static void print_tags(blkid_dev dev, char *show[], int numtag, int output)
288 {
289         blkid_tag_iterate       iter;
290         const char              *type, *value, *devname;
291         int                     i, num = 1;
292
293         if (!dev)
294                 return;
295
296         if (output & OUTPUT_PRETTY_LIST) {
297                 pretty_print_dev(dev);
298                 return;
299         }
300
301         devname = blkid_dev_devname(dev);
302
303         if (output & OUTPUT_DEVICE_ONLY) {
304                 printf("%s\n", devname);
305                 return;
306         }
307
308         iter = blkid_tag_iterate_begin(dev);
309         while (blkid_tag_next(iter, &type, &value) == 0) {
310                 if (numtag && show) {
311                         for (i=0; i < numtag; i++)
312                                 if (!strcmp(type, show[i]))
313                                         break;
314                         if (i >= numtag)
315                                 continue;
316                 }
317                 print_value(output, num++, devname, value, type, strlen(value));
318         }
319         blkid_tag_iterate_end(iter);
320
321         if (num > 1 && !(output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST)))
322                 printf("\n");
323 }
324
325 static int lowprobe_device(blkid_probe pr, const char *devname, int output,
326                 blkid_loff_t offset, blkid_loff_t size)
327 {
328         const char *data;
329         const char *name;
330         int nvals = 0, n;
331         size_t len;
332         int fd;
333         int rc = 0;
334
335         fd = open(devname, O_RDONLY);
336         if (fd < 0)
337                 return 2;
338
339         if (blkid_probe_set_device(pr, fd, offset, size))
340                 goto done;
341         rc = blkid_do_safeprobe(pr);
342         if (rc)
343                 goto done;
344
345         nvals = blkid_probe_numof_values(pr);
346
347         if (output & OUTPUT_DEVICE_ONLY) {
348                 printf("%s\n", devname);
349                 goto done;
350         }
351
352         for (n = 0; n < nvals; n++) {
353                 if (blkid_probe_get_value(pr, n, &name, &data, &len))
354                         continue;
355
356                 len = strnlen((char *) data, len);
357                 print_value(output, n + 1, devname, (char *) data, name, len);
358         }
359
360         if (nvals > 1 && !(output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST)))
361                 printf("\n");
362 done:
363         if (rc == -2)
364                 fprintf(stderr, "%s: ambivalent result "
365                                 "(probably more filesystems on the device)\n",
366                                 devname);
367         close(fd);
368         return !nvals ? 2 : 0;
369 }
370
371 /* converts comma separated list to BLKID_USAGE_* mask */
372 static int list_to_usage(const char *list, int *flag)
373 {
374         int mask = 0;
375         const char *word, *p = list;
376
377         if (p && strncmp(p, "no", 2) == 0) {
378                 *flag = BLKID_FLTR_NOTIN;
379                 p += 2;
380         }
381
382         for (word = p; p && *p; p++) {
383                 if (*p == ',' || *(p + 1) == '\0') {
384                         if (!strncmp(word, "filesystem", 10))
385                                 mask |= BLKID_USAGE_FILESYSTEM;
386                         else if (!strncmp(word, "raid", 4))
387                                 mask |= BLKID_USAGE_RAID;
388                         else if (!strncmp(word, "crypto", 6))
389                                 mask |= BLKID_USAGE_CRYPTO;
390                         else if (!strncmp(word, "other", 5))
391                                 mask |= BLKID_USAGE_OTHER;
392                         else {
393                                 fprintf(stderr, "unknown usage keyword '%*s'\n",
394                                                 (int) (p - word), word);
395                                 exit(4);
396                         }
397                         word = p + 1;
398                 }
399         }
400         return mask;
401 }
402
403 int main(int argc, char **argv)
404 {
405         blkid_cache cache = NULL;
406         char *devices[128] = { NULL, };
407         char *show[128] = { NULL, };
408         char *search_type = NULL, *search_value = NULL;
409         char *read = NULL;
410         char *write = NULL;
411         int fltr_usage = 0;
412         int fltr_flag = BLKID_FLTR_ONLYIN;
413         unsigned int numdev = 0, numtag = 0;
414         int version = 0;
415         int err = 4;
416         unsigned int i;
417         int output_format = 0;
418         int lookup = 0, gc = 0, lowprobe = 0, eval = 0;
419         int c;
420         blkid_loff_t offset = 0, size = 0;
421
422         while ((c = getopt (argc, argv, "c:f:ghlL:o:O:ps:S:t:u:U:w:v")) != EOF)
423                 switch (c) {
424                 case 'c':
425                         if (optarg && !*optarg)
426                                 read = NULL;
427                         else
428                                 read = optarg;
429                         if (!write)
430                                 write = read;
431                         break;
432                 case 'L':
433                         eval++;
434                         search_value = strdup(optarg);
435                         search_type = strdup("LABEL");
436                         break;
437                 case 'u':
438                         fltr_usage = list_to_usage(optarg, &fltr_flag);
439                         break;
440                 case 'U':
441                         eval++;
442                         search_value = strdup(optarg);
443                         search_type = strdup("UUID");
444                         break;
445                 case 'l':
446                         lookup++;
447                         break;
448                 case 'g':
449                         gc = 1;
450                         break;
451                 case 'o':
452                         if (!strcmp(optarg, "value"))
453                                 output_format = OUTPUT_VALUE_ONLY;
454                         else if (!strcmp(optarg, "device"))
455                                 output_format = OUTPUT_DEVICE_ONLY;
456                         else if (!strcmp(optarg, "list"))
457                                 output_format = OUTPUT_PRETTY_LIST;
458                         else if (!strcmp(optarg, "udev"))
459                                 output_format = OUTPUT_UDEV_LIST;
460                         else if (!strcmp(optarg, "full"))
461                                 output_format = 0;
462                         else {
463                                 fprintf(stderr, "Invalid output format %s. "
464                                         "Choose from value,\n\t"
465                                         "device, list, udev or full\n", optarg);
466                                 exit(4);
467                         }
468                         break;
469                 case 'O':
470                         offset = strtoll(optarg, NULL, 10);
471                         break;
472                 case 'p':
473                         lowprobe++;
474                         break;
475                 case 's':
476                         if (numtag >= sizeof(show) / sizeof(*show)) {
477                                 fprintf(stderr, "Too many tags specified\n");
478                                 usage(err);
479                         }
480                         show[numtag++] = optarg;
481                         break;
482                 case 'S':
483                         size = strtoll(optarg, NULL, 10);
484                         break;
485                 case 't':
486                         if (search_type) {
487                                 fprintf(stderr, "Can only search for "
488                                                 "one NAME=value pair\n");
489                                 usage(err);
490                         }
491                         if (blkid_parse_tag_string(optarg,
492                                                    &search_type,
493                                                    &search_value)) {
494                                 fprintf(stderr, "-t needs NAME=value pair\n");
495                                 usage(err);
496                         }
497                         break;
498                 case 'v':
499                         version = 1;
500                         break;
501                 case 'w':
502                         if (optarg && !*optarg)
503                                 write = NULL;
504                         else
505                                 write = optarg;
506                         break;
507                 case 'h':
508                         err = 0;
509                 default:
510                         usage(err);
511                 }
512
513         while (optind < argc)
514                 devices[numdev++] = argv[optind++];
515
516         if (version) {
517                 print_version(stdout);
518                 goto exit;
519         }
520
521         /* convert LABEL/UUID lookup to evaluate request */
522         if (lookup && output_format == OUTPUT_DEVICE_ONLY && search_type &&
523             (!strcmp(search_type, "LABEL") || !strcmp(search_type, "UUID"))) {
524                 eval++;
525                 lookup = 0;
526         }
527
528         if (!lowprobe && !eval && blkid_get_cache(&cache, read) < 0)
529                 goto exit;
530
531         if (gc) {
532                 blkid_gc_cache(cache);
533                 err = 0;
534                 goto exit;
535         }
536         err = 2;
537
538         if (output_format & OUTPUT_PRETTY_LIST)
539                 pretty_print_dev(NULL);
540
541         if (lowprobe) {
542                 /*
543                  * Low-level API
544                  */
545                 blkid_probe pr;
546
547                 if (!numdev) {
548                         fprintf(stderr, "The low-probe option requires a device\n");
549                         exit(4);
550                 }
551                 pr = blkid_new_probe();
552                 if (!pr)
553                         goto exit;
554                 blkid_probe_set_request(pr,
555                                 BLKID_PROBREQ_LABEL | BLKID_PROBREQ_UUID |
556                                 BLKID_PROBREQ_TYPE | BLKID_PROBREQ_SECTYPE |
557                                 BLKID_PROBREQ_USAGE | BLKID_PROBREQ_VERSION);
558                 if (fltr_usage &&
559                     blkid_probe_filter_usage(pr, fltr_flag, fltr_usage))
560                         goto exit;
561
562                 for (i = 0; i < numdev; i++)
563                         err = lowprobe_device(pr, devices[i],
564                                         output_format, offset, size);
565                 blkid_free_probe(pr);
566         } else if (eval) {
567                 /*
568                  * Evaluate API
569                  */
570                 char *res = blkid_evaluate_tag(search_type, search_value, NULL);
571                 if (res) {
572                         err = 0;
573                         printf("%s\n", res);
574                 }
575         } else if (lookup) {
576                 /*
577                  * Classic (cache based) API
578                  */
579                 blkid_dev dev;
580
581                 if (!search_type) {
582                         fprintf(stderr, "The lookup option requires a "
583                                 "search type specified using -t\n");
584                         exit(4);
585                 }
586                 /* Load any additional devices not in the cache */
587                 for (i = 0; i < numdev; i++)
588                         blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL);
589
590                 if ((dev = blkid_find_dev_with_tag(cache, search_type,
591                                                    search_value))) {
592                         print_tags(dev, show, numtag, output_format);
593                         err = 0;
594                 }
595         /* If we didn't specify a single device, show all available devices */
596         } else if (!numdev) {
597                 blkid_dev_iterate       iter;
598                 blkid_dev               dev;
599
600                 blkid_probe_all(cache);
601
602                 iter = blkid_dev_iterate_begin(cache);
603                 blkid_dev_set_search(iter, search_type, search_value);
604                 while (blkid_dev_next(iter, &dev) == 0) {
605                         dev = blkid_verify(cache, dev);
606                         if (!dev)
607                                 continue;
608                         print_tags(dev, show, numtag, output_format);
609                         err = 0;
610                 }
611                 blkid_dev_iterate_end(iter);
612         /* Add all specified devices to cache (optionally display tags) */
613         } else for (i = 0; i < numdev; i++) {
614                 blkid_dev dev = blkid_get_dev(cache, devices[i],
615                                                   BLKID_DEV_NORMAL);
616
617                 if (dev) {
618                         if (search_type &&
619                             !blkid_dev_has_tag(dev, search_type,
620                                                search_value))
621                                 continue;
622                         print_tags(dev, show, numtag, output_format);
623                         err = 0;
624                 }
625         }
626
627 exit:
628         free(search_type);
629         free(search_value);
630         if (!lowprobe && !eval)
631                 blkid_put_cache(cache);
632         return err;
633 }