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 fputc(ch, stdout); 91 } 92 } 93 94 static int get_terminal_width(void) 95 { 96 #ifdef TIOCGSIZE 97 struct ttysize t_win; 98 #endif 99 #ifdef TIOCGWINSZ 100 struct winsize w_win; 101 #endif 102 const char *cp; 103 int width = 80; 104 105 #ifdef TIOCGSIZE 106 if (ioctl (0, TIOCGSIZE, &t_win) == 0) { 107 width = t_win.ts_cols; 108 goto got_it; 109 } 110 #endif 111 #ifdef TIOCGWINSZ 112 if (ioctl (0, TIOCGWINSZ, &w_win) == 0) { 113 width = w_win.ws_col; 114 goto got_it; 115 } 116 #endif 117 cp = getenv("COLUMNS"); 118 if (cp) 119 width = atoi(cp); 120 got_it: 121 if (width > 4096) 122 return 4096; /* sanity check */ 123 return width; 124 } 125 126 static int pretty_print_word(const char *str, int max_len, 127 int left_len, int overflow_nl) 128 { 129 int len = strlen(str) + left_len; 130 int ret = 0; 131 132 fputs(str, stdout); 133 if (overflow_nl && len > max_len) { 134 fputc('\n', stdout); 135 len = 0; 136 } else if (len > max_len) 137 ret = len - max_len; 138 do { 139 fputc(' ', stdout); 140 } while (len++ < max_len); 141 return ret; 142 } 143 144 static void pretty_print_line(const char *device, const char *fs_type, 145 const char *label, const char *mtpt, 146 const char *uuid) 147 { 148 static int device_len = 10, fs_type_len = 7; 149 static int label_len = 8, mtpt_len = 14; 150 static int term_width = -1; 151 int len, w; 152 153 if (term_width < 0) { 154 term_width = get_terminal_width(); 155 156 if (term_width > 80) { 157 term_width -= 80; 158 w = term_width / 10; 159 if (w > 8) 160 w = 8; 161 term_width -= 2*w; 162 label_len += w; 163 fs_type_len += w; 164 w = term_width/2; 165 device_len += w; 166 mtpt_len +=w; 167 } 168 } 169 170 len = pretty_print_word(device, device_len, 0, 1); 171 len = pretty_print_word(fs_type, fs_type_len, len, 0); 172 len = pretty_print_word(label, label_len, len, 0); 173 len = pretty_print_word(mtpt, mtpt_len, len, 0); 174 fputs(uuid, stdout); 175 fputc('\n', stdout); 176 } 177 178 static void pretty_print_dev(blkid_dev dev) 179 { 180 blkid_tag_iterate iter; 181 const char *type, *value, *devname; 182 const char *uuid = "", *fs_type = "", *label = ""; 183 int len, mount_flags; 184 char mtpt[80]; 185 errcode_t retval; 186 187 if (dev == NULL) { 188 pretty_print_line("device", "fs_type", "label", 189 "mount point", "UUID"); 190 for (len=get_terminal_width()-1; len > 0; len--) 191 fputc('-', stdout); 192 fputc('\n', stdout); 193 return; 194 } 195 196 devname = blkid_dev_devname(dev); 197 if (access(devname, F_OK)) 198 return; 199 200 /* Get the uuid, label, type */ 201 iter = blkid_tag_iterate_begin(dev); 202 while (blkid_tag_next(iter, &type, &value) == 0) { 203 if (!strcmp(type, "UUID")) 204 uuid = value; 205 if (!strcmp(type, "TYPE")) 206 fs_type = value; 207 if (!strcmp(type, "LABEL")) 208 label = value; 209 } 210 blkid_tag_iterate_end(iter); 211 212 /* Get the mount point */ 213 mtpt[0] = 0; 214 retval = ext2fs_check_mount_point(devname, &mount_flags, 215 mtpt, sizeof(mtpt)); 216 if (retval == 0) { 217 if (mount_flags & EXT2_MF_MOUNTED) { 218 if (!mtpt[0]) 219 strcpy(mtpt, "(mounted, mtpt unknown)"); 220 } else if (mount_flags & EXT2_MF_BUSY) 221 strcpy(mtpt, "(in use)"); 222 else 223 strcpy(mtpt, "(not mounted)"); 224 } 225 226 pretty_print_line(devname, fs_type, label, mtpt, uuid); 227 } 228 229 static void print_tags(blkid_dev dev, char *show[], int numtag, int output) 230 { 231 blkid_tag_iterate iter; 232 const char *type, *value; 233 int i, first = 1; 234 235 if (!dev) 236 return; 237 238 if (output & OUTPUT_PRETTY_LIST) { 239 pretty_print_dev(dev); 240 return; 241 } 242 243 if (output & OUTPUT_DEVICE_ONLY) { 244 printf("%s\n", blkid_dev_devname(dev)); 245 return; 246 } 247 248 iter = blkid_tag_iterate_begin(dev); 249 while (blkid_tag_next(iter, &type, &value) == 0) { 250 if (numtag && show) { 251 for (i=0; i < numtag; i++) 252 if (!strcmp(type, show[i])) 253 break; 254 if (i >= numtag) 255 continue; 256 } 257 if (output & OUTPUT_VALUE_ONLY) { 258 fputs(value, stdout); 259 fputc('\n', stdout); 260 } else { 261 if (first) { 262 printf("%s: ", blkid_dev_devname(dev)); 263 first = 0; 264 } 265 fputs(type, stdout); 266 fputs("=\"", stdout); 267 safe_print(value, -1); 268 fputs("\" ", stdout); 269 } 270 } 271 blkid_tag_iterate_end(iter); 272 273 if (!first && !(output & OUTPUT_VALUE_ONLY)) 274 printf("\n"); 275 } 276 277 int main(int argc, char **argv) 278 { 279 blkid_cache cache = NULL; 280 char *devices[128] = { NULL, }; 281 char *show[128] = { NULL, }; 282 char *search_type = NULL, *search_value = NULL; 283 char *read = NULL; 284 char *write = NULL; 285 unsigned int numdev = 0, numtag = 0; 286 int version = 0; 287 int err = 4; 288 unsigned int i; 289 int output_format = 0; 290 int lookup = 0, gc = 0; 291 int c; 292 293 while ((c = getopt (argc, argv, "c:f:ghlLo:s:t:w:v")) != EOF) 294 switch (c) { 295 case 'c': 296 read = optarg; 297 if (!write) 298 write = read; 299 break; 300 case 'l': 301 lookup++; 302 break; 303 case 'L': 304 output_format = OUTPUT_PRETTY_LIST; 305 break; 306 case 'g': 307 gc = 1; 308 break; 309 case 'o': 310 if (!strcmp(optarg, "value")) 311 output_format = OUTPUT_VALUE_ONLY; 312 else if (!strcmp(optarg, "device")) 313 output_format = OUTPUT_DEVICE_ONLY; 314 else if (!strcmp(optarg, "list")) 315 output_format = OUTPUT_PRETTY_LIST; 316 else if (!strcmp(optarg, "full")) 317 output_format = 0; 318 else { 319 fprintf(stderr, "Invalid output format %s. " 320 "Choose from value,\n\t" 321 "device, list, or full\n", optarg); 322 exit(1); 323 } 324 break; 325 case 's': 326 if (numtag >= sizeof(show) / sizeof(*show)) { 327 fprintf(stderr, "Too many tags specified\n"); 328 usage(err); 329 } 330 show[numtag++] = optarg; 331 break; 332 case 't': 333 if (search_type) { 334 fprintf(stderr, "Can only search for " 335 "one NAME=value pair\n"); 336 usage(err); 337 } 338 if (blkid_parse_tag_string(optarg, 339 &search_type, 340 &search_value)) { 341 fprintf(stderr, "-t needs NAME=value pair\n"); 342 usage(err); 343 } 344 break; 345 case 'v': 346 version = 1; 347 break; 348 case 'w': 349 write = optarg; 350 break; 351 case 'h': 352 err = 0; 353 /* fallthrough */ 354 default: 355 usage(err); 356 } 357 358 while (optind < argc) 359 devices[numdev++] = argv[optind++]; 360 361 if (version) { 362 print_version(stdout); 363 goto exit; 364 } 365 366 if (blkid_get_cache(&cache, read) < 0) 367 goto exit; 368 369 err = 2; 370 if (gc) { 371 blkid_gc_cache(cache); 372 goto exit; 373 } 374 if (output_format & OUTPUT_PRETTY_LIST) 375 pretty_print_dev(NULL); 376 377 if (lookup) { 378 blkid_dev dev; 379 380 if (!search_type) { 381 fprintf(stderr, "The lookup option requires a " 382 "search type specified using -t\n"); 383 exit(1); 384 } 385 /* Load any additional devices not in the cache */ 386 for (i = 0; i < numdev; i++) 387 blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL); 388 389 if ((dev = blkid_find_dev_with_tag(cache, search_type, 390 search_value))) { 391 print_tags(dev, show, numtag, output_format); 392 err = 0; 393 } 394 /* If we didn't specify a single device, show all available devices */ 395 } else if (!numdev) { 396 blkid_dev_iterate iter; 397 blkid_dev dev; 398 399 blkid_probe_all(cache); 400 401 iter = blkid_dev_iterate_begin(cache); 402 blkid_dev_set_search(iter, search_type, search_value); 403 while (blkid_dev_next(iter, &dev) == 0) { 404 dev = blkid_verify(cache, dev); 405 if (!dev) 406 continue; 407 print_tags(dev, show, numtag, output_format); 408 err = 0; 409 } 410 blkid_dev_iterate_end(iter); 411 /* Add all specified devices to cache (optionally display tags) */ 412 } else for (i = 0; i < numdev; i++) { 413 blkid_dev dev = blkid_get_dev(cache, devices[i], 414 BLKID_DEV_NORMAL); 415 416 if (dev) { 417 if (search_type && 418 !blkid_dev_has_tag(dev, search_type, 419 search_value)) 420 continue; 421 print_tags(dev, show, numtag, output_format); 422 err = 0; 423 } 424 } 425 426 exit: 427 free(search_type); 428 free(search_value); 429 blkid_put_cache(cache); 430 return err; 431 } 432