libmtd.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356
  1. /*
  2. * Copyright (c) International Business Machines Corp., 2006
  3. * Copyright (C) 2009 Nokia Corporation
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  13. * the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. *
  19. * Author: Artem Bityutskiy
  20. *
  21. * MTD library.
  22. */
  23. #include <limits.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <errno.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <dirent.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <sys/ioctl.h>
  33. #include <inttypes.h>
  34. #include <mtd/mtd-user.h>
  35. #include <libmtd.h>
  36. #include "libmtd_int.h"
  37. #include "common.h"
  38. /**
  39. * mkpath - compose full path from 2 given components.
  40. * @path: the first component
  41. * @name: the second component
  42. *
  43. * This function returns the resulting path in case of success and %NULL in
  44. * case of failure.
  45. */
  46. static char *mkpath(const char *path, const char *name)
  47. {
  48. char *n;
  49. size_t len1 = strlen(path);
  50. size_t len2 = strlen(name);
  51. n = xmalloc(len1 + len2 + 2);
  52. memcpy(n, path, len1);
  53. if (n[len1 - 1] != '/')
  54. n[len1++] = '/';
  55. memcpy(n + len1, name, len2 + 1);
  56. return n;
  57. }
  58. /**
  59. * read_data - read data from a file.
  60. * @file: the file to read from
  61. * @buf: the buffer to read to
  62. * @buf_len: buffer length
  63. *
  64. * This function returns number of read bytes in case of success and %-1 in
  65. * case of failure. Note, if the file contains more then @buf_len bytes of
  66. * date, this function fails with %EINVAL error code.
  67. */
  68. static int read_data(const char *file, void *buf, int buf_len)
  69. {
  70. int fd, rd, tmp, tmp1;
  71. fd = open(file, O_RDONLY | O_CLOEXEC);
  72. if (fd == -1)
  73. return -1;
  74. rd = read(fd, buf, buf_len);
  75. if (rd == -1) {
  76. sys_errmsg("cannot read \"%s\"", file);
  77. goto out_error;
  78. }
  79. if (rd == buf_len) {
  80. errmsg("contents of \"%s\" is too long", file);
  81. errno = EINVAL;
  82. goto out_error;
  83. }
  84. ((char *)buf)[rd] = '\0';
  85. /* Make sure all data is read */
  86. tmp1 = read(fd, &tmp, 1);
  87. if (tmp1 == 1) {
  88. sys_errmsg("cannot read \"%s\"", file);
  89. goto out_error;
  90. }
  91. if (tmp1) {
  92. errmsg("file \"%s\" contains too much data (> %d bytes)",
  93. file, buf_len);
  94. errno = EINVAL;
  95. goto out_error;
  96. }
  97. if (close(fd)) {
  98. sys_errmsg("close failed on \"%s\"", file);
  99. return -1;
  100. }
  101. return rd;
  102. out_error:
  103. close(fd);
  104. return -1;
  105. }
  106. /**
  107. * read_major - read major and minor numbers from a file.
  108. * @file: name of the file to read from
  109. * @major: major number is returned here
  110. * @minor: minor number is returned here
  111. *
  112. * This function returns % in case of success, and %-1 in case of failure.
  113. */
  114. static int read_major(const char *file, int *major, int *minor)
  115. {
  116. int ret;
  117. char buf[50];
  118. ret = read_data(file, buf, 50);
  119. if (ret < 0)
  120. return ret;
  121. ret = sscanf(buf, "%d:%d\n", major, minor);
  122. if (ret != 2) {
  123. errno = EINVAL;
  124. return errmsg("\"%s\" does not have major:minor format", file);
  125. }
  126. if (*major < 0 || *minor < 0) {
  127. errno = EINVAL;
  128. return errmsg("bad major:minor %d:%d in \"%s\"",
  129. *major, *minor, file);
  130. }
  131. return 0;
  132. }
  133. /**
  134. * dev_get_major - get major and minor numbers of an MTD device.
  135. * @lib: libmtd descriptor
  136. * @mtd_num: MTD device number
  137. * @major: major number is returned here
  138. * @minor: minor number is returned here
  139. *
  140. * This function returns zero in case of success and %-1 in case of failure.
  141. */
  142. static int dev_get_major(struct libmtd *lib, int mtd_num, int *major, int *minor)
  143. {
  144. char file[strlen(lib->mtd_dev) + 50];
  145. sprintf(file, lib->mtd_dev, mtd_num);
  146. return read_major(file, major, minor);
  147. }
  148. /**
  149. * dev_read_data - read data from an MTD device's sysfs file.
  150. * @patt: file pattern to read from
  151. * @mtd_num: MTD device number
  152. * @buf: buffer to read to
  153. * @buf_len: buffer length
  154. *
  155. * This function returns number of read bytes in case of success and %-1 in
  156. * case of failure.
  157. */
  158. static int dev_read_data(const char *patt, int mtd_num, void *buf, int buf_len)
  159. {
  160. char file[strlen(patt) + 100];
  161. sprintf(file, patt, mtd_num);
  162. return read_data(file, buf, buf_len);
  163. }
  164. /**
  165. * read_hex_ll - read a hex 'long long' value from a file.
  166. * @file: the file to read from
  167. * @value: the result is stored here
  168. *
  169. * This function reads file @file and interprets its contents as hexadecimal
  170. * 'long long' integer. If this is not true, it fails with %EINVAL error code.
  171. * Returns %0 in case of success and %-1 in case of failure.
  172. */
  173. static int read_hex_ll(const char *file, long long *value)
  174. {
  175. int fd, rd;
  176. char buf[50];
  177. fd = open(file, O_RDONLY | O_CLOEXEC);
  178. if (fd == -1)
  179. return -1;
  180. rd = read(fd, buf, sizeof(buf));
  181. if (rd == -1) {
  182. sys_errmsg("cannot read \"%s\"", file);
  183. goto out_error;
  184. }
  185. if (rd == sizeof(buf)) {
  186. errmsg("contents of \"%s\" is too long", file);
  187. errno = EINVAL;
  188. goto out_error;
  189. }
  190. buf[rd] = '\0';
  191. *value = 0;
  192. if (sscanf(buf, "%llx\n", value) != 1) {
  193. errmsg("cannot read integer from \"%s\"\n", file);
  194. errno = EINVAL;
  195. goto out_error;
  196. }
  197. if (*value < 0) {
  198. errmsg("negative value %lld in \"%s\"", *value, file);
  199. errno = EINVAL;
  200. goto out_error;
  201. }
  202. if (close(fd))
  203. return sys_errmsg("close failed on \"%s\"", file);
  204. return 0;
  205. out_error:
  206. close(fd);
  207. return -1;
  208. }
  209. /**
  210. * read_pos_ll - read a positive 'long long' value from a file.
  211. * @file: the file to read from
  212. * @value: the result is stored here
  213. *
  214. * This function reads file @file and interprets its contents as a positive
  215. * 'long long' integer. If this is not true, it fails with %EINVAL error code.
  216. * Returns %0 in case of success and %-1 in case of failure.
  217. */
  218. static int read_pos_ll(const char *file, long long *value)
  219. {
  220. int fd, rd;
  221. char buf[50];
  222. memset(buf, 0, 50);
  223. fd = open(file, O_RDONLY | O_CLOEXEC);
  224. if (fd == -1)
  225. return -1;
  226. rd = read(fd, buf, 50);
  227. if (rd == -1) {
  228. sys_errmsg("cannot read \"%s\"", file);
  229. goto out_error;
  230. }
  231. if (rd == 50) {
  232. errmsg("contents of \"%s\" is too long", file);
  233. errno = EINVAL;
  234. goto out_error;
  235. }
  236. *value = 0;
  237. if (sscanf(buf, "%lld\n", value) != 1) {
  238. errmsg("cannot read integer from \"%s\"\n", file);
  239. errno = EINVAL;
  240. goto out_error;
  241. }
  242. if (*value < 0) {
  243. errmsg("negative value %lld in \"%s\"", *value, file);
  244. errno = EINVAL;
  245. goto out_error;
  246. }
  247. if (close(fd))
  248. return sys_errmsg("close failed on \"%s\"", file);
  249. return 0;
  250. out_error:
  251. close(fd);
  252. return -1;
  253. }
  254. /**
  255. * read_hex_int - read an 'int' value from a file.
  256. * @file: the file to read from
  257. * @value: the result is stored here
  258. *
  259. * This function is the same as 'read_pos_ll()', but it reads an 'int'
  260. * value, not 'long long'.
  261. */
  262. static int read_hex_int(const char *file, int *value)
  263. {
  264. long long res;
  265. if (read_hex_ll(file, &res))
  266. return -1;
  267. /* Make sure the value has correct range */
  268. if (res > INT_MAX || res < INT_MIN) {
  269. errmsg("value %lld read from file \"%s\" is out of range",
  270. res, file);
  271. errno = EINVAL;
  272. return -1;
  273. }
  274. *value = res;
  275. return 0;
  276. }
  277. /**
  278. * read_pos_int - read a positive 'int' value from a file.
  279. * @file: the file to read from
  280. * @value: the result is stored here
  281. *
  282. * This function is the same as 'read_pos_ll()', but it reads an 'int'
  283. * value, not 'long long'.
  284. */
  285. static int read_pos_int(const char *file, int *value)
  286. {
  287. long long res;
  288. if (read_pos_ll(file, &res))
  289. return -1;
  290. /* Make sure the value is not too big */
  291. if (res > INT_MAX) {
  292. errmsg("value %lld read from file \"%s\" is out of range",
  293. res, file);
  294. errno = EINVAL;
  295. return -1;
  296. }
  297. *value = res;
  298. return 0;
  299. }
  300. /**
  301. * dev_read_hex_int - read an hex 'int' value from an MTD device sysfs file.
  302. * @patt: file pattern to read from
  303. * @mtd_num: MTD device number
  304. * @value: the result is stored here
  305. *
  306. * This function returns %0 in case of success and %-1 in case of failure.
  307. */
  308. static int dev_read_hex_int(const char *patt, int mtd_num, int *value)
  309. {
  310. char file[strlen(patt) + 50];
  311. sprintf(file, patt, mtd_num);
  312. return read_hex_int(file, value);
  313. }
  314. /**
  315. * dev_read_pos_int - read a positive 'int' value from an MTD device sysfs file.
  316. * @patt: file pattern to read from
  317. * @mtd_num: MTD device number
  318. * @value: the result is stored here
  319. *
  320. * This function returns %0 in case of success and %-1 in case of failure.
  321. */
  322. static int dev_read_pos_int(const char *patt, int mtd_num, int *value)
  323. {
  324. char file[strlen(patt) + 50];
  325. sprintf(file, patt, mtd_num);
  326. return read_pos_int(file, value);
  327. }
  328. /**
  329. * dev_read_pos_ll - read a positive 'long long' value from an MTD device sysfs file.
  330. * @patt: file pattern to read from
  331. * @mtd_num: MTD device number
  332. * @value: the result is stored here
  333. *
  334. * This function returns %0 in case of success and %-1 in case of failure.
  335. */
  336. static int dev_read_pos_ll(const char *patt, int mtd_num, long long *value)
  337. {
  338. char file[strlen(patt) + 50];
  339. sprintf(file, patt, mtd_num);
  340. return read_pos_ll(file, value);
  341. }
  342. /**
  343. * type_str2int - convert MTD device type to integer.
  344. * @str: MTD device type string to convert
  345. *
  346. * This function converts MTD device type string @str, read from sysfs, into an
  347. * integer.
  348. */
  349. static int type_str2int(const char *str)
  350. {
  351. if (!strcmp(str, "nand"))
  352. return MTD_NANDFLASH;
  353. if (!strcmp(str, "mlc-nand"))
  354. return MTD_MLCNANDFLASH;
  355. if (!strcmp(str, "nor"))
  356. return MTD_NORFLASH;
  357. if (!strcmp(str, "rom"))
  358. return MTD_ROM;
  359. if (!strcmp(str, "absent"))
  360. return MTD_ABSENT;
  361. if (!strcmp(str, "dataflash"))
  362. return MTD_DATAFLASH;
  363. if (!strcmp(str, "ram"))
  364. return MTD_RAM;
  365. if (!strcmp(str, "ubi"))
  366. return MTD_UBIVOLUME;
  367. return -1;
  368. }
  369. /**
  370. * dev_node2num - find MTD device number by its character device node.
  371. * @lib: MTD library descriptor
  372. * @node: name of the MTD device node
  373. * @mtd_num: MTD device number is returned here
  374. *
  375. * This function returns %0 in case of success and %-1 in case of failure.
  376. */
  377. static int dev_node2num(struct libmtd *lib, const char *node, int *mtd_num)
  378. {
  379. struct stat st;
  380. int i, mjr, mnr;
  381. struct mtd_info info;
  382. if (stat(node, &st))
  383. return sys_errmsg("cannot get information about \"%s\"", node);
  384. if (!S_ISCHR(st.st_mode)) {
  385. errmsg("\"%s\" is not a character device", node);
  386. errno = EINVAL;
  387. return -1;
  388. }
  389. mjr = major(st.st_rdev);
  390. mnr = minor(st.st_rdev);
  391. if (mtd_get_info((libmtd_t *)lib, &info))
  392. return -1;
  393. for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
  394. int mjr1, mnr1, ret;
  395. ret = dev_get_major(lib, i, &mjr1, &mnr1);
  396. if (ret) {
  397. if (errno == ENOENT)
  398. continue;
  399. if (!errno)
  400. break;
  401. return -1;
  402. }
  403. if (mjr1 == mjr && mnr1 == mnr) {
  404. errno = 0;
  405. *mtd_num = i;
  406. return 0;
  407. }
  408. }
  409. errno = ENODEV;
  410. return -1;
  411. }
  412. /**
  413. * sysfs_is_supported - check whether the MTD sub-system supports MTD.
  414. * @lib: MTD library descriptor
  415. *
  416. * The Linux kernel MTD subsystem gained sysfs support starting from kernel
  417. * 2.6.30 and libmtd tries to use sysfs interface if possible, because the NAND
  418. * sub-page size is available there (and not available at all in pre-sysfs
  419. * kernels).
  420. *
  421. * Very old kernels did not have "/sys/class/mtd" directory. Not very old
  422. * kernels (e.g., 2.6.29) did have "/sys/class/mtd/mtdX" directories, by there
  423. * were no files there, e.g., the "name" file was not present. So all we can do
  424. * is to check for a "/sys/class/mtd/mtdX/name" file. But this is not a
  425. * reliable check, because if this is a new system with no MTD devices - we'll
  426. * treat it as a pre-sysfs system.
  427. */
  428. static int sysfs_is_supported(struct libmtd *lib)
  429. {
  430. int fd, num = -1;
  431. DIR *sysfs_mtd;
  432. char file[strlen(lib->mtd_name) + 10];
  433. sysfs_mtd = opendir(lib->sysfs_mtd);
  434. if (!sysfs_mtd) {
  435. if (errno == ENOENT) {
  436. errno = 0;
  437. return 0;
  438. }
  439. return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
  440. }
  441. /*
  442. * First of all find an "mtdX" directory. This is needed because there
  443. * may be, for example, mtd1 but no mtd0.
  444. */
  445. while (1) {
  446. int ret, mtd_num;
  447. char tmp_buf[256];
  448. struct dirent *dirent;
  449. dirent = readdir(sysfs_mtd);
  450. if (!dirent)
  451. break;
  452. if (strlen(dirent->d_name) >= 255) {
  453. errmsg("invalid entry in %s: \"%s\"",
  454. lib->sysfs_mtd, dirent->d_name);
  455. errno = EINVAL;
  456. closedir(sysfs_mtd);
  457. return -1;
  458. }
  459. ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
  460. &mtd_num, tmp_buf);
  461. if (ret == 1) {
  462. num = mtd_num;
  463. break;
  464. }
  465. }
  466. if (closedir(sysfs_mtd))
  467. return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
  468. if (num == -1)
  469. /* No mtd device, treat this as pre-sysfs system */
  470. return 0;
  471. sprintf(file, lib->mtd_name, num);
  472. fd = open(file, O_RDONLY | O_CLOEXEC);
  473. if (fd == -1)
  474. return 0;
  475. if (close(fd)) {
  476. sys_errmsg("close failed on \"%s\"", file);
  477. return -1;
  478. }
  479. return 1;
  480. }
  481. libmtd_t libmtd_open(void)
  482. {
  483. struct libmtd *lib;
  484. lib = xzalloc(sizeof(*lib));
  485. lib->offs64_ioctls = OFFS64_IOCTLS_UNKNOWN;
  486. lib->sysfs_mtd = mkpath(SYSFS_ROOT, SYSFS_MTD);
  487. if (!lib->sysfs_mtd)
  488. goto out_error;
  489. lib->mtd = mkpath(lib->sysfs_mtd, MTD_NAME_PATT);
  490. if (!lib->mtd)
  491. goto out_error;
  492. lib->mtd_name = mkpath(lib->mtd, MTD_NAME);
  493. if (!lib->mtd_name)
  494. goto out_error;
  495. if (!sysfs_is_supported(lib)) {
  496. free(lib->mtd);
  497. free(lib->sysfs_mtd);
  498. free(lib->mtd_name);
  499. lib->mtd_name = lib->mtd = lib->sysfs_mtd = NULL;
  500. if (!legacy_procfs_is_supported()) {
  501. free(lib);
  502. lib = NULL;
  503. }
  504. return lib;
  505. }
  506. lib->mtd_dev = mkpath(lib->mtd, MTD_DEV);
  507. if (!lib->mtd_dev)
  508. goto out_error;
  509. lib->mtd_type = mkpath(lib->mtd, MTD_TYPE);
  510. if (!lib->mtd_type)
  511. goto out_error;
  512. lib->mtd_eb_size = mkpath(lib->mtd, MTD_EB_SIZE);
  513. if (!lib->mtd_eb_size)
  514. goto out_error;
  515. lib->mtd_size = mkpath(lib->mtd, MTD_SIZE);
  516. if (!lib->mtd_size)
  517. goto out_error;
  518. lib->mtd_min_io_size = mkpath(lib->mtd, MTD_MIN_IO_SIZE);
  519. if (!lib->mtd_min_io_size)
  520. goto out_error;
  521. lib->mtd_subpage_size = mkpath(lib->mtd, MTD_SUBPAGE_SIZE);
  522. if (!lib->mtd_subpage_size)
  523. goto out_error;
  524. lib->mtd_oob_size = mkpath(lib->mtd, MTD_OOB_SIZE);
  525. if (!lib->mtd_oob_size)
  526. goto out_error;
  527. lib->mtd_oobavail = mkpath(lib->mtd, MTD_OOBAVAIL);
  528. if (!lib->mtd_oobavail)
  529. goto out_error;
  530. lib->mtd_region_cnt = mkpath(lib->mtd, MTD_REGION_CNT);
  531. if (!lib->mtd_region_cnt)
  532. goto out_error;
  533. lib->mtd_flags = mkpath(lib->mtd, MTD_FLAGS);
  534. if (!lib->mtd_flags)
  535. goto out_error;
  536. lib->sysfs_supported = 1;
  537. return lib;
  538. out_error:
  539. libmtd_close((libmtd_t)lib);
  540. return NULL;
  541. }
  542. void libmtd_close(libmtd_t desc)
  543. {
  544. struct libmtd *lib = (struct libmtd *)desc;
  545. free(lib->mtd_flags);
  546. free(lib->mtd_region_cnt);
  547. free(lib->mtd_oob_size);
  548. free(lib->mtd_oobavail);
  549. free(lib->mtd_subpage_size);
  550. free(lib->mtd_min_io_size);
  551. free(lib->mtd_size);
  552. free(lib->mtd_eb_size);
  553. free(lib->mtd_type);
  554. free(lib->mtd_dev);
  555. free(lib->mtd_name);
  556. free(lib->mtd);
  557. free(lib->sysfs_mtd);
  558. free(lib);
  559. }
  560. int mtd_dev_present(libmtd_t desc, int mtd_num) {
  561. struct stat st;
  562. struct libmtd *lib = (struct libmtd *)desc;
  563. if (!lib->sysfs_supported) {
  564. return legacy_dev_present(mtd_num) == 1;
  565. } else {
  566. char file[strlen(lib->mtd) + 10];
  567. sprintf(file, lib->mtd, mtd_num);
  568. return !stat(file, &st);
  569. }
  570. }
  571. int mtd_get_info(libmtd_t desc, struct mtd_info *info)
  572. {
  573. DIR *sysfs_mtd;
  574. struct dirent *dirent;
  575. struct libmtd *lib = (struct libmtd *)desc;
  576. memset(info, 0, sizeof(struct mtd_info));
  577. if (!lib->sysfs_supported)
  578. return legacy_mtd_get_info(info);
  579. info->sysfs_supported = 1;
  580. /*
  581. * We have to scan the MTD sysfs directory to identify how many MTD
  582. * devices are present.
  583. */
  584. sysfs_mtd = opendir(lib->sysfs_mtd);
  585. if (!sysfs_mtd)
  586. return sys_errmsg("cannot open \"%s\"", lib->sysfs_mtd);
  587. info->lowest_mtd_num = INT_MAX;
  588. while (1) {
  589. int mtd_num, ret;
  590. char tmp_buf[256];
  591. errno = 0;
  592. dirent = readdir(sysfs_mtd);
  593. if (!dirent)
  594. break;
  595. if (strlen(dirent->d_name) >= 255) {
  596. errmsg("invalid entry in %s: \"%s\"",
  597. lib->sysfs_mtd, dirent->d_name);
  598. errno = EINVAL;
  599. goto out_close;
  600. }
  601. ret = sscanf(dirent->d_name, MTD_NAME_PATT"%s",
  602. &mtd_num, tmp_buf);
  603. if (ret == 1) {
  604. info->mtd_dev_cnt += 1;
  605. if (mtd_num > info->highest_mtd_num)
  606. info->highest_mtd_num = mtd_num;
  607. if (mtd_num < info->lowest_mtd_num)
  608. info->lowest_mtd_num = mtd_num;
  609. }
  610. }
  611. if (!dirent && errno) {
  612. sys_errmsg("readdir failed on \"%s\"", lib->sysfs_mtd);
  613. goto out_close;
  614. }
  615. if (closedir(sysfs_mtd))
  616. return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_mtd);
  617. if (info->lowest_mtd_num == INT_MAX)
  618. info->lowest_mtd_num = 0;
  619. return 0;
  620. out_close:
  621. closedir(sysfs_mtd);
  622. return -1;
  623. }
  624. int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd)
  625. {
  626. int ret;
  627. struct libmtd *lib = (struct libmtd *)desc;
  628. memset(mtd, 0, sizeof(struct mtd_dev_info));
  629. mtd->mtd_num = mtd_num;
  630. if (!mtd_dev_present(desc, mtd_num)) {
  631. errno = ENODEV;
  632. return -1;
  633. } else if (!lib->sysfs_supported)
  634. return legacy_get_dev_info1(mtd_num, mtd);
  635. if (dev_get_major(lib, mtd_num, &mtd->major, &mtd->minor))
  636. return -1;
  637. ret = dev_read_data(lib->mtd_name, mtd_num, (char *)&mtd->name,
  638. MTD_NAME_MAX + 1);
  639. if (ret < 0)
  640. return -1;
  641. ((char *)mtd->name)[ret - 1] = '\0';
  642. ret = dev_read_data(lib->mtd_type, mtd_num, (char *)&mtd->type_str,
  643. MTD_TYPE_MAX + 1);
  644. if (ret < 0)
  645. return -1;
  646. ((char *)mtd->type_str)[ret - 1] = '\0';
  647. if (dev_read_pos_int(lib->mtd_eb_size, mtd_num, &mtd->eb_size))
  648. return -1;
  649. if (dev_read_pos_ll(lib->mtd_size, mtd_num, &mtd->size))
  650. return -1;
  651. if (dev_read_pos_int(lib->mtd_min_io_size, mtd_num, &mtd->min_io_size))
  652. return -1;
  653. if (dev_read_pos_int(lib->mtd_subpage_size, mtd_num, &mtd->subpage_size))
  654. return -1;
  655. if (dev_read_pos_int(lib->mtd_oob_size, mtd_num, &mtd->oob_size))
  656. return -1;
  657. if (dev_read_pos_int(lib->mtd_oobavail, mtd_num, &mtd->oobavail)) {
  658. /*
  659. * Fail to access oobavail sysfs file,
  660. * try ioctl ECCGETLAYOUT. */
  661. mtd->oobavail = legacy_get_mtd_oobavail1(mtd_num);
  662. /* Set 0 as default if can not get valid ecc layout */
  663. if (mtd->oobavail < 0)
  664. mtd->oobavail = 0;
  665. }
  666. if (dev_read_pos_int(lib->mtd_region_cnt, mtd_num, &mtd->region_cnt))
  667. return -1;
  668. if (dev_read_hex_int(lib->mtd_flags, mtd_num, &ret))
  669. return -1;
  670. mtd->writable = !!(ret & MTD_WRITEABLE);
  671. mtd->eb_cnt = mtd->size / mtd->eb_size;
  672. mtd->type = type_str2int(mtd->type_str);
  673. mtd->bb_allowed = !!(mtd->type == MTD_NANDFLASH ||
  674. mtd->type == MTD_MLCNANDFLASH);
  675. return 0;
  676. }
  677. int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd)
  678. {
  679. int mtd_num;
  680. struct libmtd *lib = (struct libmtd *)desc;
  681. if (!lib->sysfs_supported)
  682. return legacy_get_dev_info(node, mtd);
  683. if (dev_node2num(lib, node, &mtd_num))
  684. return -1;
  685. return mtd_get_dev_info1(desc, mtd_num, mtd);
  686. }
  687. static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb,
  688. const char *sreq)
  689. {
  690. return sys_errmsg("%s ioctl failed for eraseblock %d (mtd%d)",
  691. sreq, eb, mtd->mtd_num);
  692. }
  693. static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
  694. {
  695. if (eb < 0 || eb >= mtd->eb_cnt) {
  696. errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
  697. eb, mtd->mtd_num, mtd->eb_cnt);
  698. errno = EINVAL;
  699. return -1;
  700. }
  701. return 0;
  702. }
  703. static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
  704. const char *sreq)
  705. {
  706. int ret;
  707. struct erase_info_user ei;
  708. ret = mtd_valid_erase_block(mtd, eb);
  709. if (ret)
  710. return ret;
  711. ei.start = eb * mtd->eb_size;
  712. ei.length = mtd->eb_size;
  713. ret = ioctl(fd, req, &ei);
  714. if (ret < 0)
  715. return mtd_ioctl_error(mtd, eb, sreq);
  716. return 0;
  717. }
  718. #define mtd_xlock(mtd, fd, eb, req) mtd_xlock(mtd, fd, eb, req, #req)
  719. int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb)
  720. {
  721. return mtd_xlock(mtd, fd, eb, MEMLOCK);
  722. }
  723. int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb)
  724. {
  725. return mtd_xlock(mtd, fd, eb, MEMUNLOCK);
  726. }
  727. int mtd_erase_multi(libmtd_t desc, const struct mtd_dev_info *mtd,
  728. int fd, int eb, int blocks)
  729. {
  730. int ret;
  731. struct libmtd *lib = (struct libmtd *)desc;
  732. struct erase_info_user64 ei64;
  733. struct erase_info_user ei;
  734. ret = mtd_valid_erase_block(mtd, eb);
  735. if (ret)
  736. return ret;
  737. ret = mtd_valid_erase_block(mtd, eb + blocks - 1);
  738. if (ret)
  739. return ret;
  740. ei64.start = (__u64)eb * mtd->eb_size;
  741. ei64.length = (__u64)mtd->eb_size * blocks;
  742. if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
  743. lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
  744. ret = ioctl(fd, MEMERASE64, &ei64);
  745. if (ret == 0)
  746. return ret;
  747. if (errno != ENOTTY ||
  748. lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN)
  749. return mtd_ioctl_error(mtd, eb, "MEMERASE64");
  750. /*
  751. * MEMERASE64 support was added in kernel version 2.6.31, so
  752. * probably we are working with older kernel and this ioctl is
  753. * not supported.
  754. */
  755. lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
  756. }
  757. if (ei64.start + ei64.length > 0xFFFFFFFF) {
  758. errmsg("this system can address only %u eraseblocks",
  759. 0xFFFFFFFFU / mtd->eb_size);
  760. errno = EINVAL;
  761. return -1;
  762. }
  763. ei.start = ei64.start;
  764. ei.length = ei64.length;
  765. ret = ioctl(fd, MEMERASE, &ei);
  766. if (ret < 0)
  767. return mtd_ioctl_error(mtd, eb, "MEMERASE");
  768. return 0;
  769. }
  770. int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
  771. {
  772. return mtd_erase_multi(desc, mtd, fd, eb, 1);
  773. }
  774. int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo)
  775. {
  776. int ret;
  777. if (regidx < 0) {
  778. errno = ENODEV;
  779. return -1;
  780. }
  781. reginfo->regionindex = regidx;
  782. ret = ioctl(fd, MEMGETREGIONINFO, reginfo);
  783. if (ret < 0)
  784. return sys_errmsg("%s ioctl failed for erase region %d",
  785. "MEMGETREGIONINFO", regidx);
  786. return 0;
  787. }
  788. int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb)
  789. {
  790. int ret;
  791. erase_info_t ei;
  792. ei.start = eb * mtd->eb_size;
  793. ei.length = mtd->eb_size;
  794. ret = ioctl(fd, MEMISLOCKED, &ei);
  795. if (ret < 0) {
  796. if (errno != ENOTTY && errno != EOPNOTSUPP)
  797. return mtd_ioctl_error(mtd, eb, "MEMISLOCKED");
  798. else
  799. errno = EOPNOTSUPP;
  800. }
  801. return ret;
  802. }
  803. /* Patterns to write to a physical eraseblock when torturing it */
  804. static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
  805. /**
  806. * check_pattern - check if buffer contains only a certain byte pattern.
  807. * @buf: buffer to check
  808. * @patt: the pattern to check
  809. * @size: buffer size in bytes
  810. *
  811. * This function returns %0 if there are only @patt bytes in @buf, and %-1 if
  812. * something else was also found.
  813. */
  814. static int check_pattern(const void *buf, uint8_t patt, int size)
  815. {
  816. int i;
  817. for (i = 0; i < size; i++)
  818. if (((const uint8_t *)buf)[i] != patt)
  819. return -1;
  820. return 0;
  821. }
  822. int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)
  823. {
  824. int err, i, patt_count;
  825. void *buf;
  826. normsg("run torture test for PEB %d", eb);
  827. patt_count = ARRAY_SIZE(patterns);
  828. buf = xmalloc(mtd->eb_size);
  829. for (i = 0; i < patt_count; i++) {
  830. err = mtd_erase(desc, mtd, fd, eb);
  831. if (err)
  832. goto out;
  833. /* Make sure the PEB contains only 0xFF bytes */
  834. err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
  835. if (err)
  836. goto out;
  837. err = check_pattern(buf, 0xFF, mtd->eb_size);
  838. if (err) {
  839. errmsg("erased PEB %d, but a non-0xFF byte found", eb);
  840. errno = EIO;
  841. goto out;
  842. }
  843. /* Write a pattern and check it */
  844. memset(buf, patterns[i], mtd->eb_size);
  845. err = mtd_write(desc, mtd, fd, eb, 0, buf, mtd->eb_size, NULL,
  846. 0, 0);
  847. if (err)
  848. goto out;
  849. memset(buf, ~patterns[i], mtd->eb_size);
  850. err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
  851. if (err)
  852. goto out;
  853. err = check_pattern(buf, patterns[i], mtd->eb_size);
  854. if (err) {
  855. errmsg("pattern %x checking failed for PEB %d",
  856. patterns[i], eb);
  857. errno = EIO;
  858. goto out;
  859. }
  860. }
  861. err = 0;
  862. normsg("PEB %d passed torture test, do not mark it a bad", eb);
  863. out:
  864. free(buf);
  865. return err;
  866. }
  867. int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
  868. {
  869. int ret;
  870. loff_t seek;
  871. ret = mtd_valid_erase_block(mtd, eb);
  872. if (ret)
  873. return ret;
  874. if (!mtd->bb_allowed)
  875. return 0;
  876. seek = (loff_t)eb * mtd->eb_size;
  877. ret = ioctl(fd, MEMGETBADBLOCK, &seek);
  878. if (ret == -1)
  879. return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK");
  880. return ret;
  881. }
  882. int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb)
  883. {
  884. int ret;
  885. loff_t seek;
  886. if (!mtd->bb_allowed) {
  887. errno = EINVAL;
  888. return -1;
  889. }
  890. ret = mtd_valid_erase_block(mtd, eb);
  891. if (ret)
  892. return ret;
  893. seek = (loff_t)eb * mtd->eb_size;
  894. ret = ioctl(fd, MEMSETBADBLOCK, &seek);
  895. if (ret == -1)
  896. return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK");
  897. return 0;
  898. }
  899. int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
  900. void *buf, int len)
  901. {
  902. int ret, rd = 0;
  903. off_t seek;
  904. ret = mtd_valid_erase_block(mtd, eb);
  905. if (ret)
  906. return ret;
  907. if (offs < 0 || offs + len > mtd->eb_size) {
  908. errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
  909. offs, len, mtd->mtd_num, mtd->eb_size);
  910. errno = EINVAL;
  911. return -1;
  912. }
  913. /* Seek to the beginning of the eraseblock */
  914. seek = (off_t)eb * mtd->eb_size + offs;
  915. if (lseek(fd, seek, SEEK_SET) != seek)
  916. return sys_errmsg("cannot seek mtd%d to offset %lld",
  917. mtd->mtd_num, (long long)seek);
  918. while (rd < len) {
  919. ret = read(fd, buf + rd, len - rd);
  920. if (ret < 0)
  921. return sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
  922. len - rd, mtd->mtd_num, eb, offs + rd);
  923. rd += ret;
  924. }
  925. return 0;
  926. }
  927. static int legacy_auto_oob_layout(const struct mtd_dev_info *mtd, int fd,
  928. int ooblen, void *oob) {
  929. struct nand_oobinfo old_oobinfo;
  930. int start, len;
  931. uint8_t *tmp_buf;
  932. /* Read the current oob info */
  933. if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo))
  934. return sys_errmsg("MEMGETOOBSEL failed");
  935. tmp_buf = malloc(ooblen);
  936. memcpy(tmp_buf, oob, ooblen);
  937. /*
  938. * We use autoplacement and have the oobinfo with the autoplacement
  939. * information from the kernel available
  940. */
  941. if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
  942. int i, tags_pos = 0;
  943. for (i = 0; old_oobinfo.oobfree[i][1]; i++) {
  944. /* Set the reserved bytes to 0xff */
  945. start = old_oobinfo.oobfree[i][0];
  946. len = old_oobinfo.oobfree[i][1];
  947. memcpy(oob + start, tmp_buf + tags_pos, len);
  948. tags_pos += len;
  949. }
  950. } else {
  951. /* Set at least the ecc byte positions to 0xff */
  952. start = old_oobinfo.eccbytes;
  953. len = mtd->oob_size - start;
  954. memcpy(oob + start, tmp_buf + start, len);
  955. }
  956. free(tmp_buf);
  957. return 0;
  958. }
  959. int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
  960. int offs, void *data, int len, void *oob, int ooblen,
  961. uint8_t mode)
  962. {
  963. int ret;
  964. off_t seek;
  965. struct mtd_write_req ops;
  966. memset(&ops, 0, sizeof(ops));
  967. ret = mtd_valid_erase_block(mtd, eb);
  968. if (ret)
  969. return ret;
  970. if (offs < 0 || offs + len > mtd->eb_size) {
  971. errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
  972. offs, len, mtd->mtd_num, mtd->eb_size);
  973. errno = EINVAL;
  974. return -1;
  975. }
  976. if (offs % mtd->subpage_size) {
  977. errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
  978. offs, mtd->mtd_num, mtd->subpage_size);
  979. errno = EINVAL;
  980. return -1;
  981. }
  982. if (len % mtd->subpage_size) {
  983. errmsg("write length %d is not aligned to mtd%d min. I/O size %d",
  984. len, mtd->mtd_num, mtd->subpage_size);
  985. errno = EINVAL;
  986. return -1;
  987. }
  988. /* Calculate seek address */
  989. seek = (off_t)eb * mtd->eb_size + offs;
  990. if (oob) {
  991. ops.start = seek;
  992. ops.len = len;
  993. ops.ooblen = ooblen;
  994. ops.usr_data = (uint64_t)(unsigned long)data;
  995. ops.usr_oob = (uint64_t)(unsigned long)oob;
  996. ops.mode = mode;
  997. ret = ioctl(fd, MEMWRITE, &ops);
  998. if (ret == 0)
  999. return 0;
  1000. else if (errno != ENOTTY && errno != EOPNOTSUPP)
  1001. return mtd_ioctl_error(mtd, eb, "MEMWRITE");
  1002. /* Fall back to old OOB ioctl() if necessary */
  1003. if (mode == MTD_OPS_AUTO_OOB)
  1004. if (legacy_auto_oob_layout(mtd, fd, ooblen, oob))
  1005. return -1;
  1006. if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0)
  1007. return sys_errmsg("cannot write to OOB");
  1008. }
  1009. if (data) {
  1010. /* Seek to the beginning of the eraseblock */
  1011. if (lseek(fd, seek, SEEK_SET) != seek)
  1012. return sys_errmsg("cannot seek mtd%d to offset %lld",
  1013. mtd->mtd_num, (long long)seek);
  1014. ret = write(fd, data, len);
  1015. if (ret != len)
  1016. return sys_errmsg("cannot write %d bytes to mtd%d "
  1017. "(eraseblock %d, offset %d)",
  1018. len, mtd->mtd_num, eb, offs);
  1019. }
  1020. return 0;
  1021. }
  1022. static int do_oob_op(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
  1023. uint64_t start, uint64_t length, void *data,
  1024. unsigned int cmd64, unsigned int cmd)
  1025. {
  1026. int ret, oob_offs;
  1027. struct mtd_oob_buf64 oob64;
  1028. struct mtd_oob_buf oob;
  1029. unsigned long long max_offs;
  1030. const char *cmd64_str, *cmd_str;
  1031. struct libmtd *lib = (struct libmtd *)desc;
  1032. memset(&oob64, 0, sizeof(oob64));
  1033. memset(&oob, 0, sizeof(oob));
  1034. if (cmd64 == MEMREADOOB64) {
  1035. cmd64_str = "MEMREADOOB64";
  1036. cmd_str = "MEMREADOOB";
  1037. } else {
  1038. cmd64_str = "MEMWRITEOOB64";
  1039. cmd_str = "MEMWRITEOOB";
  1040. }
  1041. max_offs = (unsigned long long)mtd->eb_cnt * mtd->eb_size;
  1042. if (start >= max_offs) {
  1043. errmsg("bad page address %" PRIu64 ", mtd%d has %d eraseblocks (%llu bytes)",
  1044. start, mtd->mtd_num, mtd->eb_cnt, max_offs);
  1045. errno = EINVAL;
  1046. return -1;
  1047. }
  1048. oob_offs = start & (mtd->min_io_size - 1);
  1049. if (oob_offs + length > mtd->oob_size || length == 0) {
  1050. errmsg("Cannot write %" PRIu64 " OOB bytes to address %" PRIu64 " (OOB offset %u) - mtd%d OOB size is only %d bytes",
  1051. length, start, oob_offs, mtd->mtd_num, mtd->oob_size);
  1052. errno = EINVAL;
  1053. return -1;
  1054. }
  1055. oob64.start = start;
  1056. oob64.length = length;
  1057. oob64.usr_ptr = (uint64_t)(unsigned long)data;
  1058. if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED ||
  1059. lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) {
  1060. ret = ioctl(fd, cmd64, &oob64);
  1061. if (ret == 0)
  1062. return ret;
  1063. if (errno != ENOTTY ||
  1064. lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) {
  1065. sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
  1066. cmd64_str, mtd->mtd_num, start, start / mtd->eb_size);
  1067. }
  1068. /*
  1069. * MEMREADOOB64/MEMWRITEOOB64 support was added in kernel
  1070. * version 2.6.31, so probably we are working with older kernel
  1071. * and these ioctls are not supported.
  1072. */
  1073. lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
  1074. }
  1075. if (oob64.start > 0xFFFFFFFFULL) {
  1076. errmsg("this system can address only up to address %lu",
  1077. 0xFFFFFFFFUL);
  1078. errno = EINVAL;
  1079. return -1;
  1080. }
  1081. oob.start = oob64.start;
  1082. oob.length = oob64.length;
  1083. oob.ptr = data;
  1084. ret = ioctl(fd, cmd, &oob);
  1085. if (ret < 0)
  1086. sys_errmsg("%s ioctl failed for mtd%d, offset %" PRIu64 " (eraseblock %" PRIu64 ")",
  1087. cmd_str, mtd->mtd_num, start, start / mtd->eb_size);
  1088. return ret;
  1089. }
  1090. int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
  1091. uint64_t start, uint64_t length, void *data)
  1092. {
  1093. return do_oob_op(desc, mtd, fd, start, length, data,
  1094. MEMREADOOB64, MEMREADOOB);
  1095. }
  1096. int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
  1097. uint64_t start, uint64_t length, void *data)
  1098. {
  1099. return do_oob_op(desc, mtd, fd, start, length, data,
  1100. MEMWRITEOOB64, MEMWRITEOOB);
  1101. }
  1102. int mtd_probe_node(libmtd_t desc, const char *node)
  1103. {
  1104. struct stat st;
  1105. struct mtd_info info;
  1106. int i, mjr, mnr;
  1107. struct libmtd *lib = (struct libmtd *)desc;
  1108. if (stat(node, &st))
  1109. return sys_errmsg("cannot get information about \"%s\"", node);
  1110. if (!S_ISCHR(st.st_mode)) {
  1111. errmsg("\"%s\" is not a character device", node);
  1112. errno = EINVAL;
  1113. return -1;
  1114. }
  1115. mjr = major(st.st_rdev);
  1116. mnr = minor(st.st_rdev);
  1117. if (mtd_get_info((libmtd_t *)lib, &info))
  1118. return -1;
  1119. if (!lib->sysfs_supported)
  1120. return 0;
  1121. for (i = info.lowest_mtd_num; i <= info.highest_mtd_num; i++) {
  1122. int mjr1, mnr1, ret;
  1123. ret = dev_get_major(lib, i, &mjr1, &mnr1);
  1124. if (ret) {
  1125. if (errno == ENOENT)
  1126. continue;
  1127. if (!errno)
  1128. break;
  1129. return -1;
  1130. }
  1131. if (mjr1 == mjr && mnr1 == mnr)
  1132. return 1;
  1133. }
  1134. errno = 0;
  1135. return -1;
  1136. }