lsmtd.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. /*
  2. * Copyright (C) 2017 David Oberhollenzer - sigma star gmbh
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License version 2 as published by
  6. * the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along with
  14. * this program; see the file COPYING. If not, write to the Free Software
  15. * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA.
  16. *
  17. * Author: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
  18. */
  19. #include <getopt.h>
  20. #include <stdio.h>
  21. #include "lsmtd.h"
  22. #define FLAG_SI 0x0001
  23. #define FLAG_BYTES 0x0002
  24. #define FLAG_NO_HEADING 0x0004
  25. #define FLAG_RAW 0x0008
  26. #define FLAG_PAIRS 0x0010
  27. #define FLAG_LIST 0x0020
  28. #define FLAG_JSON 0x0040
  29. #define FLAG_ASCII 0x0080
  30. #define FLAG_NO_UBI 0x0100
  31. #define FLAG_DRYRUN 0x1000
  32. static int flags;
  33. static struct column **selected;
  34. static size_t num_selected;
  35. static size_t max_selected;
  36. struct column *sort_by;
  37. static const struct option long_opts[] = {
  38. { "help", no_argument, NULL, 'h' },
  39. { "version", no_argument, NULL, 'V' },
  40. { "si-units", no_argument, NULL, 'u' },
  41. { "bytes", no_argument, NULL, 'b' },
  42. { "noheadings", no_argument, NULL, 'n' },
  43. { "raw", no_argument, NULL, 'r' },
  44. { "output", required_argument, NULL, 'o' },
  45. { "output-all", no_argument, NULL, 'O' },
  46. { "pairs", no_argument, NULL, 'P' },
  47. { "list", no_argument, NULL, 'l' },
  48. { "json", no_argument, NULL, 'J' },
  49. { "sort", required_argument, NULL, 'x' },
  50. { "ascii", no_argument, NULL, 'i' },
  51. { "no-ubi", no_argument, NULL, 'm' },
  52. { NULL, 0, NULL, 0 },
  53. };
  54. static const char *short_opts = "x:o:OPJlibrumnhV";
  55. static const char *default_cols = "DEVICE,MAJ:MIN,NAME,TYPE,SIZE";
  56. static struct column cols[] = {
  57. { "DEVICE", "name of the device node", COL_DEVNAME, COL_DT_STRING, 0 },
  58. { "MAJ:MIN", "major:minor device number",
  59. COL_DEVNUM, COL_DT_STRING, 0 },
  60. { "NAME", "device name string", COL_NAME, COL_DT_STRING, 0 },
  61. { "TYPE", "device type", COL_TYPE, COL_DT_STRING, 0 },
  62. { "SIZE", "size of the device", COL_SIZE, COL_DT_SIZE, 0 },
  63. { "EB-SIZE", "erase block size", COL_EBSIZE, COL_DT_SIZE, 0 },
  64. { "EB-COUNT", "number of erase blocks", COL_EBCOUNT, COL_DT_NUMBER, 0 },
  65. { "MIN-IO", "minimum I/O size", COL_MINIO, COL_DT_SIZE, 0 },
  66. { "SUB-SIZE", "subpage size", COL_SUBSIZE, COL_DT_SIZE, 0 },
  67. { "OOB-SIZE", "out of band data size", COL_OOBSIZE, COL_DT_SIZE, 0 },
  68. { "RO", "read-only device", COL_RO, COL_DT_BOOL, 0 },
  69. { "CORRUPTED", "wheather an UBI volume is corrupted",
  70. COL_CORRUPTED, COL_DT_BOOL, 0 },
  71. { "REGIONS", "number of additional erase regions",
  72. COL_REGION, COL_DT_NUMBER, 0 },
  73. { "BB", "wheather the MTD device may have bad eraseblocks",
  74. COL_BB, COL_DT_BOOL, 0 },
  75. { "MAX-EC", "current highest erase counter value on UBI devices",
  76. COL_MAXEC, COL_DT_NUMBER, 0 },
  77. { "FREE", "available bytes on an UBI device or volume",
  78. COL_FREE, COL_DT_SIZE, 0 },
  79. { "FREE-LEB", "available LEBs on an UBI device or volume",
  80. COL_FREE_LEB, COL_DT_NUMBER, 0 },
  81. { "BAD-COUNT", "number of bad physical eraseblocks",
  82. COL_BAD_COUNT, COL_DT_NUMBER, 0 },
  83. { "BAD-RSVD", "number of reserved eraseblocks for bad block handling",
  84. COL_BAD_RSVD, COL_DT_NUMBER, 0 },
  85. };
  86. static NORETURN void usage(int status)
  87. {
  88. FILE *outstream = status == EXIT_SUCCESS ? stdout : stderr;
  89. size_t i, len, max_len = 0;
  90. fputs(
  91. "Usage: "PROGRAM_NAME" [options] [<device> ...]\n\n"
  92. "List information about memory technology devices.\n\n"
  93. "Options:\n"
  94. " -u, --si-units Scale sizes by factors of 1000 instead of 1024\n"
  95. " -b, --bytes Print sizes in bytes\n"
  96. " -i, --ascii Use ascii characters only\n"
  97. " -l, --list Use list output format (default)\n"
  98. " -n, --noheadings Don't print a heading\n"
  99. " -r, --raw Use raw output format\n"
  100. " -P, --pairs Use key=\"value\" output format\n"
  101. " -J, --json Use JSON output format\n"
  102. " -o, --output <list> Comma seperated list of columns to print\n"
  103. " -O, --output-all Print all columns\n"
  104. " -x, --sort <column> Sort output by <column>\n"
  105. " -m, --no-ubi Do not display information about UBI devices/volumes\n"
  106. "\n"
  107. " -h, --help Display this help text and exit\n"
  108. " -V, --version Output version information and exit\n"
  109. "\n"
  110. "Available columns (for --output, --sort):\n",
  111. outstream);
  112. for (i = 0; i < sizeof(cols) / sizeof(cols[0]); ++i) {
  113. len = strlen(cols[i].name);
  114. max_len = len > max_len ? len : max_len;
  115. }
  116. for (i = 0; i < sizeof(cols) / sizeof(cols[0]); ++i) {
  117. fprintf(outstream, " %*s %s\n", (int)max_len, cols[i].name,
  118. cols[i].desc);
  119. }
  120. fputs("\nFor more details see "PROGRAM_NAME"(8).\n", stdout);
  121. exit(status);
  122. }
  123. static NORETURN void version(int status)
  124. {
  125. common_print_version();
  126. fputs(
  127. "Copyright (C) 2017 David Oberhollenzer - sigma star gmbh\n"
  128. "License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl2.html>.\n"
  129. "This is free software: you are free to change and redistribute it.\n"
  130. "There is NO WARRANTY, to the extent permitted by law.\n\n"
  131. "Written by David Oberhollenzer.\n",
  132. stdout);
  133. exit(status);
  134. }
  135. static struct column *column_by_name(const char *name, size_t len)
  136. {
  137. size_t i;
  138. for (i = 0; i < sizeof(cols) / sizeof(cols[0]); ++i) {
  139. if (strncmp(cols[i].name, name, len) != 0)
  140. continue;
  141. if (strlen(cols[i].name) == len)
  142. return cols + i;
  143. }
  144. return NULL;
  145. }
  146. static int process_col_list(const char *list)
  147. {
  148. struct column *col;
  149. const char *end;
  150. size_t len;
  151. if (*list == '+') {
  152. ++list;
  153. } else {
  154. num_selected = 0;
  155. }
  156. while (*list) {
  157. end = strchrnul(list, ',');
  158. len = end - list;
  159. col = column_by_name(list, len);
  160. if (!col) {
  161. fprintf(stderr, "Unknown column '%.*s'\n",
  162. (int)len, list);
  163. return -1;
  164. }
  165. if (num_selected == max_selected) {
  166. max_selected = max_selected ? max_selected * 2 : 10;
  167. selected = xrealloc(selected, max_selected *
  168. sizeof(*selected));
  169. }
  170. selected[num_selected++] = col;
  171. list = *end ? end + 1 : end;
  172. }
  173. return 0;
  174. }
  175. static void select_all(void)
  176. {
  177. size_t i;
  178. num_selected = sizeof(cols) / sizeof(cols[0]);
  179. if (max_selected < num_selected) {
  180. max_selected = num_selected;
  181. selected = xrealloc(selected, max_selected * sizeof(*selected));
  182. }
  183. for (i = 0; i < num_selected; ++i)
  184. selected[i] = cols + i;
  185. }
  186. static void process_args(int argc, char **argv)
  187. {
  188. int i;
  189. process_col_list(default_cols);
  190. while (1) {
  191. i = getopt_long(argc, argv, short_opts, long_opts, NULL);
  192. if (i == -1)
  193. break;
  194. switch (i) {
  195. case 'x':
  196. sort_by = column_by_name(optarg, strlen(optarg));
  197. if (!sort_by) {
  198. fprintf(stderr, "Unknown column '%s'\n",
  199. optarg);
  200. goto fail;
  201. }
  202. break;
  203. case 'o':
  204. if (process_col_list(optarg) != 0)
  205. goto fail;
  206. break;
  207. case 'O':
  208. select_all();
  209. break;
  210. case 'i': flags |= FLAG_ASCII; break;
  211. case 'J': flags |= FLAG_JSON; break;
  212. case 'P': flags |= FLAG_PAIRS; break;
  213. case 'l': flags |= FLAG_LIST; break;
  214. case 'b': flags |= FLAG_BYTES; break;
  215. case 'r': flags |= FLAG_RAW; break;
  216. case 'u': flags |= FLAG_SI; break;
  217. case 'n': flags |= FLAG_NO_HEADING; break;
  218. case 'm': flags |= FLAG_NO_UBI; break;
  219. case 'h': usage(EXIT_SUCCESS);
  220. case 'V': version(EXIT_SUCCESS);
  221. default: usage(EXIT_FAILURE);
  222. }
  223. }
  224. i = flags & (FLAG_LIST|FLAG_PAIRS|FLAG_RAW|FLAG_JSON);
  225. if (i & (i - 1)) {
  226. fputs(PROGRAM_NAME": these options are mutually exclusive: "
  227. "--list --pairs --raw --json\n", stderr);
  228. goto fail;
  229. } else if (!i) {
  230. flags |= FLAG_LIST;
  231. }
  232. /*if (optind < argc)
  233. list_arg = optind;*/
  234. return;
  235. fail:
  236. fputs("Try `"PROGRAM_NAME" --help` for more information\n\n", stderr);
  237. exit(EXIT_FAILURE);
  238. }
  239. static const char *tree_prefix(bool is_last)
  240. {
  241. if (is_last)
  242. return (flags & FLAG_ASCII) ? "`-" : "└─";
  243. return (flags & FLAG_ASCII) ? "|-" : "├─";
  244. }
  245. static size_t count_chars(const char *str)
  246. {
  247. size_t count = 0;
  248. while (*str) {
  249. if (((*str) & 0xC0) != 0x80)
  250. ++count;
  251. ++str;
  252. }
  253. return count;
  254. }
  255. static void devno_to_string(char *buffer, int major, int minor)
  256. {
  257. sprintf(buffer, flags & FLAG_LIST ? "%3d:%d" : "%d:%d", major, minor);
  258. }
  259. static void bool_to_string(char *buffer, int value)
  260. {
  261. if (flags & FLAG_JSON)
  262. strcpy(buffer, value ? "true" : "false");
  263. else
  264. strcpy(buffer, value ? "1" : "0");
  265. }
  266. static void size_to_string(char *buffer, long long int size)
  267. {
  268. static const char *bcdmap = "0112334456678899";
  269. static const char *suffix = "KMGTPE";
  270. int scale, idx, i, remainder = 0;
  271. if (flags & FLAG_BYTES) {
  272. sprintf(buffer, "%lld", size);
  273. return;
  274. }
  275. scale = flags & FLAG_SI ? 1000 : 1024;
  276. for (idx = -1; size >= scale && (idx < 0 || suffix[idx]); ++idx) {
  277. if (remainder >= (scale / 2)) {
  278. remainder = 0;
  279. size = (size / scale) + 1;
  280. } else {
  281. remainder = size % scale;
  282. size /= scale;
  283. }
  284. }
  285. i = sprintf(buffer, "%lld", size);
  286. remainder = (remainder >> 6) & 0x0F;
  287. if (remainder) {
  288. buffer[i++] = '.';
  289. buffer[i++] = bcdmap[remainder];
  290. }
  291. if (idx >= 0)
  292. buffer[i++] = suffix[idx];
  293. buffer[i] = '\0';
  294. }
  295. static void print_json_string(const char *value)
  296. {
  297. static const char *jsonrepl = "nrtfb", *jsonesc = "\n\r\t\f\b";
  298. const char *ptr;
  299. fputc('"', stdout);
  300. for (; *value; ++value) {
  301. ptr = strchr(jsonesc, *value);
  302. if (ptr) {
  303. fputc('\\', stdout);
  304. fputc(jsonrepl[ptr - jsonesc], stdout);
  305. } else if (*value == '\\' || *value == '"') {
  306. fputc('\\', stdout);
  307. fputc(*value, stdout);
  308. } else if (isascii(*value) &&
  309. (iscntrl(*value) || !isprint(*value))) {
  310. fprintf(stdout, "\\u%04X", *value);
  311. } else {
  312. fputc(*value, stdout);
  313. }
  314. }
  315. fputc('"', stdout);
  316. }
  317. static void print_escaped(const char *value)
  318. {
  319. while (*value) {
  320. if (iscntrl(*value) || !isprint(*value) ||
  321. *value == '\\' || *value == '"') {
  322. fprintf(stdout, "\\x%02X", *(value++));
  323. } else {
  324. fputc(*(value++), stdout);
  325. }
  326. }
  327. }
  328. static void print_padded(const char *value, bool numeric, size_t width)
  329. {
  330. size_t i;
  331. if (numeric) {
  332. fprintf(stdout, "%*s", (int)width, value);
  333. } else {
  334. for (i = 0; i < width && *value; ++i) {
  335. fputc(*(value++), stdout);
  336. while (((*value) & 0xC0) == 0x80)
  337. fputc(*(value++), stdout);
  338. }
  339. for (; i < width; ++i)
  340. fputc(' ', stdout);
  341. }
  342. }
  343. static void print_column(struct column *col, const char *value,
  344. bool is_first, int level)
  345. {
  346. bool numeric = false;
  347. const char *key;
  348. size_t colw;
  349. if (col->datatype == COL_DT_NUMBER || col->datatype == COL_DT_SIZE ||
  350. col->datatype == COL_DT_BOOL) {
  351. numeric = true;
  352. }
  353. if (flags & FLAG_JSON) {
  354. if ((col->datatype == COL_DT_SIZE) && !(flags & FLAG_BYTES))
  355. numeric = false;
  356. if (!is_first)
  357. fputs(",\n", stdout);
  358. while (level--)
  359. fputc('\t', stdout);
  360. fputc('"', stdout);
  361. for (key = col->name; *key; ++key)
  362. fputc(isupper(*key) ? tolower(*key) : *key, stdout);
  363. fputs("\": ", stdout);
  364. if (numeric) {
  365. fputs(value, stdout);
  366. } else {
  367. print_json_string(value);
  368. }
  369. } else if (flags & FLAG_DRYRUN) {
  370. colw = count_chars(value);
  371. col->width = colw > col->width ? colw : col->width;
  372. } else if (flags & FLAG_PAIRS) {
  373. if (!is_first)
  374. fputc(' ', stdout);
  375. fprintf(stdout, "%s=\"", col->name);
  376. print_escaped(value);
  377. fputs("\"", stdout);
  378. } else if (flags & FLAG_RAW) {
  379. if (!is_first)
  380. fputc(' ', stdout);
  381. print_escaped(value);
  382. } else if (flags & FLAG_LIST) {
  383. if (!is_first)
  384. fputc(' ', stdout);
  385. print_padded(value, numeric, col->width);
  386. }
  387. }
  388. static size_t print_mtd_device(struct mtd_dev_info *info)
  389. {
  390. size_t i, count = 0;
  391. const char *value;
  392. char buffer[128];
  393. for (i = 0; i < num_selected; ++i) {
  394. value = buffer;
  395. switch (selected[i]->type) {
  396. case COL_DEVNAME:
  397. sprintf(buffer, "mtd%d", info->mtd_num);
  398. break;
  399. case COL_DEVNUM:
  400. devno_to_string(buffer, info->major, info->minor);
  401. break;
  402. case COL_TYPE:
  403. value = info->type_str;
  404. break;
  405. case COL_NAME:
  406. value = info->name;
  407. break;
  408. case COL_SIZE:
  409. size_to_string(buffer, info->size);
  410. break;
  411. case COL_EBSIZE:
  412. size_to_string(buffer, info->eb_size);
  413. break;
  414. case COL_EBCOUNT:
  415. sprintf(buffer, "%d", info->eb_cnt);
  416. break;
  417. case COL_MINIO:
  418. size_to_string(buffer, info->min_io_size);
  419. break;
  420. case COL_SUBSIZE:
  421. size_to_string(buffer, info->subpage_size);
  422. break;
  423. case COL_OOBSIZE:
  424. size_to_string(buffer, info->oob_size);
  425. break;
  426. case COL_RO:
  427. bool_to_string(buffer, !info->writable);
  428. break;
  429. case COL_BB:
  430. bool_to_string(buffer, !info->bb_allowed);
  431. break;
  432. case COL_REGION:
  433. sprintf(buffer, "%d", info->region_cnt);
  434. break;
  435. default:
  436. if (flags & FLAG_JSON)
  437. continue;
  438. buffer[0] = '\0';
  439. break;
  440. }
  441. print_column(selected[i], value, i == 0, 2);
  442. ++count;
  443. }
  444. return count;
  445. }
  446. static size_t print_ubi_device(struct mtd_dev_info *mtd,
  447. struct ubi_dev_info *info)
  448. {
  449. size_t i, count = 0;
  450. char value[128];
  451. for (i = 0; i < num_selected; ++i) {
  452. switch (selected[i]->type) {
  453. case COL_DEVNAME:
  454. if (flags & FLAG_LIST) {
  455. sprintf(value, "%subi%d", tree_prefix(true),
  456. info->dev_num);
  457. } else {
  458. sprintf(value, "ubi%d", info->dev_num);
  459. }
  460. break;
  461. case COL_DEVNUM:
  462. devno_to_string(value, info->major, info->minor);
  463. break;
  464. case COL_SIZE:
  465. size_to_string(value, info->total_bytes);
  466. break;
  467. case COL_EBSIZE:
  468. size_to_string(value, info->leb_size);
  469. break;
  470. case COL_EBCOUNT:
  471. sprintf(value, "%d", info->total_lebs);
  472. break;
  473. case COL_MINIO:
  474. size_to_string(value, info->min_io_size);
  475. break;
  476. case COL_MAXEC:
  477. sprintf(value, "%lld", info->max_ec);
  478. break;
  479. case COL_FREE:
  480. size_to_string(value, info->avail_bytes);
  481. break;
  482. case COL_FREE_LEB:
  483. sprintf(value, "%d", info->avail_lebs);
  484. break;
  485. case COL_BAD_COUNT:
  486. sprintf(value, "%d", info->bad_count);
  487. break;
  488. case COL_BAD_RSVD:
  489. sprintf(value, "%d", info->bad_rsvd);
  490. break;
  491. case COL_RO:
  492. bool_to_string(value, !mtd->writable);
  493. break;
  494. default:
  495. if (flags & FLAG_JSON)
  496. continue;
  497. value[0] = '\0';
  498. break;
  499. }
  500. print_column(selected[i], value, i == 0, 3);
  501. ++count;
  502. }
  503. return count;
  504. }
  505. static size_t print_ubi_vol(struct mtd_dev_info *mtd, struct ubi_dev_info *dev,
  506. struct ubi_vol_info *info, bool is_last)
  507. {
  508. size_t i, count = 0;
  509. const char *value;
  510. char buffer[128];
  511. int used;
  512. for (i = 0; i < num_selected; ++i) {
  513. value = buffer;
  514. switch (selected[i]->type) {
  515. case COL_DEVNAME:
  516. if (flags & FLAG_LIST) {
  517. sprintf(buffer, " %subi%d_%d",
  518. tree_prefix(is_last),
  519. info->dev_num, info->vol_id);
  520. } else {
  521. sprintf(buffer, "ubi%d_%d", info->dev_num,
  522. info->vol_id);
  523. }
  524. break;
  525. case COL_DEVNUM:
  526. devno_to_string(buffer, info->major, info->minor);
  527. break;
  528. case COL_TYPE:
  529. if (info->type == UBI_DYNAMIC_VOLUME) {
  530. value = "dynamic";
  531. } else {
  532. value = "static";
  533. }
  534. break;
  535. case COL_NAME:
  536. value = info->name;
  537. break;
  538. case COL_SIZE:
  539. size_to_string(buffer, info->rsvd_bytes);
  540. break;
  541. case COL_EBSIZE:
  542. size_to_string(buffer, info->leb_size);
  543. break;
  544. case COL_EBCOUNT:
  545. sprintf(buffer, "%d", info->rsvd_lebs);
  546. break;
  547. case COL_MINIO:
  548. size_to_string(buffer, dev->min_io_size);
  549. break;
  550. case COL_FREE:
  551. size_to_string(buffer,
  552. info->rsvd_bytes - info->data_bytes);
  553. break;
  554. case COL_FREE_LEB:
  555. used = info->data_bytes / info->leb_size;
  556. sprintf(buffer, "%d", info->rsvd_lebs - used);
  557. break;
  558. case COL_RO:
  559. bool_to_string(buffer, !mtd->writable);
  560. break;
  561. case COL_CORRUPTED:
  562. bool_to_string(buffer, info->corrupted);
  563. break;
  564. default:
  565. if (flags & FLAG_JSON)
  566. continue;
  567. buffer[0] = '\0';
  568. break;
  569. }
  570. print_column(selected[i], value, i == 0, 4);
  571. ++count;
  572. }
  573. return count;
  574. }
  575. static void print_list(void)
  576. {
  577. struct ubi_node *ubi;
  578. bool is_last;
  579. size_t i;
  580. int j;
  581. if (!(flags & FLAG_NO_HEADING)) {
  582. if (flags & (FLAG_DRYRUN | FLAG_RAW)) {
  583. for (i = 0; i < num_selected; ++i)
  584. selected[i]->width = strlen(selected[i]->name);
  585. }
  586. if (!(flags & FLAG_DRYRUN)) {
  587. for (i = 0; i < num_selected; ++i) {
  588. fprintf(stdout, "%-*s ",
  589. (int)selected[i]->width,
  590. selected[i]->name);
  591. }
  592. fputc('\n', stdout);
  593. }
  594. }
  595. for (i = 0; i < num_mtd_devices; ++i) {
  596. print_mtd_device(&mtd_dev[i].info);
  597. if (!(flags & FLAG_DRYRUN))
  598. fputc('\n', stdout);
  599. ubi = mtd_dev[i].ubi;
  600. if (!ubi)
  601. continue;
  602. print_ubi_device(&mtd_dev[i].info, &ubi->info);
  603. if (!(flags & FLAG_DRYRUN))
  604. fputc('\n', stdout);
  605. for (j = 0; j < ubi->info.vol_count; ++j) {
  606. is_last = (j == (ubi->info.vol_count - 1));
  607. print_ubi_vol(&mtd_dev[i].info, &ubi->info,
  608. ubi->vol_info + j, is_last);
  609. if (!(flags & FLAG_DRYRUN))
  610. fputc('\n', stdout);
  611. }
  612. }
  613. }
  614. static void print_pairs(void)
  615. {
  616. struct ubi_node *ubi;
  617. int i, j;
  618. for (i = 0; i < num_mtd_devices; ++i) {
  619. print_mtd_device(&mtd_dev[i].info);
  620. fputc('\n', stdout);
  621. ubi = mtd_dev[i].ubi;
  622. if (ubi) {
  623. print_ubi_device(&mtd_dev[i].info, &ubi->info);
  624. fputc('\n', stdout);
  625. for (j = 0; j < ubi->info.vol_count; ++j) {
  626. print_ubi_vol(&mtd_dev[i].info, &ubi->info,
  627. ubi->vol_info + j, false);
  628. fputc('\n', stdout);
  629. }
  630. }
  631. }
  632. }
  633. static void print_json(void)
  634. {
  635. struct ubi_node *ubi;
  636. int i, j;
  637. fputs("{\n\t\"mtddevices\": [", stdout);
  638. for (i = 0; i < num_mtd_devices; ++i) {
  639. fputs(i ? ",{\n" : "{\n", stdout);
  640. if (print_mtd_device(&mtd_dev[i].info) > 0)
  641. fputs(",\n", stdout);
  642. ubi = mtd_dev[i].ubi;
  643. if (ubi) {
  644. fputs("\t\t\"ubi\": {\n", stdout);
  645. if (print_ubi_device(&mtd_dev[i].info, &ubi->info) > 0)
  646. fputs(",\n", stdout);
  647. fputs("\t\t\t\"volumes\": [", stdout);
  648. for (j = 0; j < ubi->info.vol_count; ++j) {
  649. fputs(j ? ",{\n" : "{\n", stdout);
  650. print_ubi_vol(&mtd_dev[i].info, &ubi->info,
  651. ubi->vol_info + j, false);
  652. fputs("\n\t\t\t}", stdout);
  653. }
  654. fputs("]\n\t\t}\n", stdout);
  655. } else if (!(flags & FLAG_NO_UBI)) {
  656. fputs("\t\t\"ubi\": null\n", stdout);
  657. }
  658. fputs("\t}", stdout);
  659. }
  660. fputs("]\n}\n", stdout);
  661. }
  662. int main(int argc, char **argv)
  663. {
  664. int ret, status = EXIT_FAILURE;
  665. libmtd_t lib_mtd;
  666. libubi_t lib_ubi;
  667. process_args(argc, argv);
  668. lib_mtd = libmtd_open();
  669. if (lib_mtd) {
  670. ret = scan_mtd(lib_mtd);
  671. libmtd_close(lib_mtd);
  672. if (ret)
  673. goto out;
  674. } else {
  675. if (errno) {
  676. perror("libmtd_open");
  677. return EXIT_FAILURE;
  678. }
  679. return EXIT_SUCCESS;
  680. }
  681. if (!(flags & FLAG_NO_UBI)) {
  682. lib_ubi = libubi_open();
  683. if (lib_ubi) {
  684. ret = scan_ubi(lib_ubi);
  685. libubi_close(lib_ubi);
  686. if (ret)
  687. goto out;
  688. } else if (errno) {
  689. perror("libubi_open");
  690. goto out;
  691. }
  692. }
  693. if (flags & FLAG_JSON) {
  694. print_json();
  695. } else if (flags & FLAG_PAIRS) {
  696. print_pairs();
  697. } else {
  698. flags |= FLAG_DRYRUN;
  699. print_list();
  700. flags &= ~FLAG_DRYRUN;
  701. print_list();
  702. }
  703. status = EXIT_SUCCESS;
  704. out:
  705. scan_free();
  706. free(selected);
  707. return status;
  708. }