block.c 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988
  1. /*
  2. * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3. * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License version 2.1
  7. * as published by the Free Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #define _GNU_SOURCE
  15. #include <getopt.h>
  16. #include <stdio.h>
  17. #include <unistd.h>
  18. #include <syslog.h>
  19. #include <libgen.h>
  20. #include <glob.h>
  21. #include <dirent.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <limits.h>
  27. #include <sys/stat.h>
  28. #include <sys/types.h>
  29. #include <sys/swap.h>
  30. #include <sys/mount.h>
  31. #include <sys/wait.h>
  32. #include <sys/sysmacros.h>
  33. #include <uci.h>
  34. #include <uci_blob.h>
  35. #include <libubox/avl-cmp.h>
  36. #include <libubox/blobmsg_json.h>
  37. #include <libubox/list.h>
  38. #include <libubox/ulog.h>
  39. #include <libubox/utils.h>
  40. #include <libubox/vlist.h>
  41. #include <libubus.h>
  42. #include "probe.h"
  43. #define AUTOFS_MOUNT_PATH "/tmp/run/blockd/"
  44. #ifdef UBIFS_EXTROOT
  45. #include "libubi/libubi.h"
  46. #endif
  47. enum {
  48. TYPE_MOUNT,
  49. TYPE_SWAP,
  50. };
  51. enum {
  52. TYPE_DEV,
  53. TYPE_HOTPLUG,
  54. TYPE_AUTOFS,
  55. };
  56. struct mount {
  57. struct vlist_node node;
  58. int type;
  59. char *target;
  60. char *path;
  61. char *options;
  62. uint32_t flags;
  63. char *uuid;
  64. char *label;
  65. char *device;
  66. int extroot;
  67. int autofs;
  68. int overlay;
  69. int disabled_fsck;
  70. unsigned int prio;
  71. };
  72. static struct vlist_tree mounts;
  73. static struct blob_buf b;
  74. static LIST_HEAD(devices);
  75. static int anon_mount, anon_swap, auto_mount, auto_swap, check_fs;
  76. static unsigned int delay_root;
  77. enum {
  78. CFG_ANON_MOUNT,
  79. CFG_ANON_SWAP,
  80. CFG_AUTO_MOUNT,
  81. CFG_AUTO_SWAP,
  82. CFG_DELAY_ROOT,
  83. CFG_CHECK_FS,
  84. __CFG_MAX
  85. };
  86. static const struct blobmsg_policy config_policy[__CFG_MAX] = {
  87. [CFG_ANON_SWAP] = { .name = "anon_swap", .type = BLOBMSG_TYPE_INT32 },
  88. [CFG_ANON_MOUNT] = { .name = "anon_mount", .type = BLOBMSG_TYPE_INT32 },
  89. [CFG_AUTO_SWAP] = { .name = "auto_swap", .type = BLOBMSG_TYPE_INT32 },
  90. [CFG_AUTO_MOUNT] = { .name = "auto_mount", .type = BLOBMSG_TYPE_INT32 },
  91. [CFG_DELAY_ROOT] = { .name = "delay_root", .type = BLOBMSG_TYPE_INT32 },
  92. [CFG_CHECK_FS] = { .name = "check_fs", .type = BLOBMSG_TYPE_INT32 },
  93. };
  94. enum {
  95. MOUNT_UUID,
  96. MOUNT_LABEL,
  97. MOUNT_ENABLE,
  98. MOUNT_TARGET,
  99. MOUNT_DEVICE,
  100. MOUNT_OPTIONS,
  101. MOUNT_AUTOFS,
  102. __MOUNT_MAX
  103. };
  104. static const struct uci_blob_param_list config_attr_list = {
  105. .n_params = __CFG_MAX,
  106. .params = config_policy,
  107. };
  108. static const struct blobmsg_policy mount_policy[__MOUNT_MAX] = {
  109. [MOUNT_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
  110. [MOUNT_LABEL] = { .name = "label", .type = BLOBMSG_TYPE_STRING },
  111. [MOUNT_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
  112. [MOUNT_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING },
  113. [MOUNT_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_STRING },
  114. [MOUNT_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 },
  115. [MOUNT_AUTOFS] = { .name = "autofs", .type = BLOBMSG_TYPE_INT32 },
  116. };
  117. static const struct uci_blob_param_list mount_attr_list = {
  118. .n_params = __MOUNT_MAX,
  119. .params = mount_policy,
  120. };
  121. enum {
  122. SWAP_ENABLE,
  123. SWAP_UUID,
  124. SWAP_LABEL,
  125. SWAP_DEVICE,
  126. SWAP_PRIO,
  127. __SWAP_MAX
  128. };
  129. static const struct blobmsg_policy swap_policy[__SWAP_MAX] = {
  130. [SWAP_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 },
  131. [SWAP_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
  132. [SWAP_LABEL] = { .name = "label", .type = BLOBMSG_TYPE_STRING },
  133. [SWAP_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
  134. [SWAP_PRIO] = { .name = "priority", .type = BLOBMSG_TYPE_INT32 },
  135. };
  136. static const struct uci_blob_param_list swap_attr_list = {
  137. .n_params = __SWAP_MAX,
  138. .params = swap_policy,
  139. };
  140. struct mount_flag {
  141. const char *name;
  142. int32_t flag;
  143. };
  144. static const struct mount_flag mount_flags[] = {
  145. { "sync", MS_SYNCHRONOUS },
  146. { "async", ~MS_SYNCHRONOUS },
  147. { "dirsync", MS_DIRSYNC },
  148. { "mand", MS_MANDLOCK },
  149. { "nomand", ~MS_MANDLOCK },
  150. { "atime", ~MS_NOATIME },
  151. { "noatime", MS_NOATIME },
  152. { "dev", ~MS_NODEV },
  153. { "nodev", MS_NODEV },
  154. { "diratime", ~MS_NODIRATIME },
  155. { "nodiratime", MS_NODIRATIME },
  156. { "exec", ~MS_NOEXEC },
  157. { "noexec", MS_NOEXEC },
  158. { "suid", ~MS_NOSUID },
  159. { "nosuid", MS_NOSUID },
  160. { "rw", ~MS_RDONLY },
  161. { "ro", MS_RDONLY },
  162. { "relatime", MS_RELATIME },
  163. { "norelatime", ~MS_RELATIME },
  164. { "strictatime", MS_STRICTATIME },
  165. { "acl", MS_POSIXACL },
  166. { "noacl", ~MS_POSIXACL },
  167. { "nouser_xattr", MS_NOUSER },
  168. { "user_xattr", ~MS_NOUSER },
  169. };
  170. static char *blobmsg_get_strdup(struct blob_attr *attr)
  171. {
  172. if (!attr)
  173. return NULL;
  174. return strdup(blobmsg_get_string(attr));
  175. }
  176. static char *blobmsg_get_basename(struct blob_attr *attr)
  177. {
  178. if (!attr)
  179. return NULL;
  180. return strdup(basename(blobmsg_get_string(attr)));
  181. }
  182. static void parse_mount_options(struct mount *m, char *optstr)
  183. {
  184. int i;
  185. bool is_flag;
  186. char *p, *opts, *last;
  187. m->flags = 0;
  188. m->options = NULL;
  189. if (!optstr || !*optstr)
  190. return;
  191. m->options = opts = calloc(1, strlen(optstr) + 1);
  192. if (!m->options)
  193. return;
  194. p = last = optstr;
  195. do {
  196. p = strchr(p, ',');
  197. if (p)
  198. *p++ = 0;
  199. for (i = 0, is_flag = false; i < ARRAY_SIZE(mount_flags); i++) {
  200. if (!strcmp(last, mount_flags[i].name)) {
  201. if (mount_flags[i].flag < 0)
  202. m->flags &= (uint32_t)mount_flags[i].flag;
  203. else
  204. m->flags |= (uint32_t)mount_flags[i].flag;
  205. is_flag = true;
  206. break;
  207. }
  208. }
  209. if (!is_flag)
  210. opts += sprintf(opts, "%s%s", (opts > m->options) ? "," : "", last);
  211. last = p;
  212. } while (p);
  213. free(optstr);
  214. }
  215. static int mount_add(struct uci_section *s)
  216. {
  217. struct blob_attr *tb[__MOUNT_MAX] = { 0 };
  218. struct mount *m;
  219. blob_buf_init(&b, 0);
  220. uci_to_blob(&b, s, &mount_attr_list);
  221. blobmsg_parse(mount_policy, __MOUNT_MAX, tb, blob_data(b.head), blob_len(b.head));
  222. if (!tb[MOUNT_LABEL] && !tb[MOUNT_UUID] && !tb[MOUNT_DEVICE])
  223. return -1;
  224. if (tb[MOUNT_ENABLE] && !blobmsg_get_u32(tb[MOUNT_ENABLE]))
  225. return -1;
  226. m = malloc(sizeof(struct mount));
  227. m->type = TYPE_MOUNT;
  228. m->uuid = blobmsg_get_strdup(tb[MOUNT_UUID]);
  229. m->label = blobmsg_get_strdup(tb[MOUNT_LABEL]);
  230. m->target = blobmsg_get_strdup(tb[MOUNT_TARGET]);
  231. m->device = blobmsg_get_basename(tb[MOUNT_DEVICE]);
  232. if (tb[MOUNT_AUTOFS])
  233. m->autofs = blobmsg_get_u32(tb[MOUNT_AUTOFS]);
  234. else
  235. m->autofs = 0;
  236. parse_mount_options(m, blobmsg_get_strdup(tb[MOUNT_OPTIONS]));
  237. m->overlay = m->extroot = 0;
  238. if (m->target && !strcmp(m->target, "/"))
  239. m->extroot = 1;
  240. if (m->target && !strcmp(m->target, "/overlay"))
  241. m->extroot = m->overlay = 1;
  242. if (m->target && *m->target != '/') {
  243. ULOG_WARN("ignoring mount section %s due to invalid target '%s'\n",
  244. s->e.name, m->target);
  245. free(m);
  246. return -1;
  247. }
  248. if (m->uuid)
  249. vlist_add(&mounts, &m->node, m->uuid);
  250. else if (m->label)
  251. vlist_add(&mounts, &m->node, m->label);
  252. else if (m->device)
  253. vlist_add(&mounts, &m->node, m->device);
  254. return 0;
  255. }
  256. static int swap_add(struct uci_section *s)
  257. {
  258. struct blob_attr *tb[__SWAP_MAX] = { 0 };
  259. struct mount *m;
  260. blob_buf_init(&b, 0);
  261. uci_to_blob(&b, s, &swap_attr_list);
  262. blobmsg_parse(swap_policy, __SWAP_MAX, tb, blob_data(b.head), blob_len(b.head));
  263. if (!tb[SWAP_UUID] && !tb[SWAP_LABEL] && !tb[SWAP_DEVICE])
  264. return -1;
  265. m = malloc(sizeof(struct mount));
  266. memset(m, 0, sizeof(struct mount));
  267. m->type = TYPE_SWAP;
  268. m->uuid = blobmsg_get_strdup(tb[SWAP_UUID]);
  269. m->label = blobmsg_get_strdup(tb[SWAP_LABEL]);
  270. m->device = blobmsg_get_basename(tb[SWAP_DEVICE]);
  271. if (tb[SWAP_PRIO])
  272. m->prio = blobmsg_get_u32(tb[SWAP_PRIO]);
  273. if (m->prio)
  274. m->prio = ((m->prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER;
  275. if ((!tb[SWAP_ENABLE]) || blobmsg_get_u32(tb[SWAP_ENABLE])) {
  276. /* store complete swap path */
  277. if (tb[SWAP_DEVICE])
  278. m->target = blobmsg_get_strdup(tb[SWAP_DEVICE]);
  279. if (m->uuid)
  280. vlist_add(&mounts, &m->node, m->uuid);
  281. else if (m->label)
  282. vlist_add(&mounts, &m->node, m->label);
  283. else if (m->device)
  284. vlist_add(&mounts, &m->node, m->device);
  285. }
  286. return 0;
  287. }
  288. static int global_add(struct uci_section *s)
  289. {
  290. struct blob_attr *tb[__CFG_MAX] = { 0 };
  291. blob_buf_init(&b, 0);
  292. uci_to_blob(&b, s, &config_attr_list);
  293. blobmsg_parse(config_policy, __CFG_MAX, tb, blob_data(b.head), blob_len(b.head));
  294. if ((tb[CFG_ANON_MOUNT]) && blobmsg_get_u32(tb[CFG_ANON_MOUNT]))
  295. anon_mount = 1;
  296. if ((tb[CFG_ANON_SWAP]) && blobmsg_get_u32(tb[CFG_ANON_SWAP]))
  297. anon_swap = 1;
  298. if ((tb[CFG_AUTO_MOUNT]) && blobmsg_get_u32(tb[CFG_AUTO_MOUNT]))
  299. auto_mount = 1;
  300. if ((tb[CFG_AUTO_SWAP]) && blobmsg_get_u32(tb[CFG_AUTO_SWAP]))
  301. auto_swap = 1;
  302. if (tb[CFG_DELAY_ROOT])
  303. delay_root = blobmsg_get_u32(tb[CFG_DELAY_ROOT]);
  304. if ((tb[CFG_CHECK_FS]) && blobmsg_get_u32(tb[CFG_CHECK_FS]))
  305. check_fs = 1;
  306. return 0;
  307. }
  308. static struct mount* find_swap(const char *uuid, const char *label, const char *device)
  309. {
  310. struct mount *m;
  311. vlist_for_each_element(&mounts, m, node) {
  312. if (m->type != TYPE_SWAP)
  313. continue;
  314. if (uuid && m->uuid && !strcasecmp(m->uuid, uuid))
  315. return m;
  316. if (label && m->label && !strcmp(m->label, label))
  317. return m;
  318. if (device && m->device && !strcmp(m->device, device))
  319. return m;
  320. }
  321. return NULL;
  322. }
  323. static struct mount* find_block(const char *uuid, const char *label, const char *device,
  324. const char *target)
  325. {
  326. struct mount *m;
  327. vlist_for_each_element(&mounts, m, node) {
  328. if (m->type != TYPE_MOUNT)
  329. continue;
  330. if (m->uuid && uuid && !strcasecmp(m->uuid, uuid))
  331. return m;
  332. if (m->label && label && !strcmp(m->label, label))
  333. return m;
  334. if (m->target && target && !strcmp(m->target, target))
  335. return m;
  336. if (m->device && device && !strcmp(m->device, device))
  337. return m;
  338. }
  339. return NULL;
  340. }
  341. static void mounts_update(struct vlist_tree *tree, struct vlist_node *node_new,
  342. struct vlist_node *node_old)
  343. {
  344. }
  345. static struct uci_package * config_try_load(struct uci_context *ctx, char *path)
  346. {
  347. char *file = basename(path);
  348. char *dir = dirname(path);
  349. char *err;
  350. struct uci_package *pkg;
  351. uci_set_confdir(ctx, dir);
  352. ULOG_INFO("attempting to load %s/%s\n", dir, file);
  353. if (uci_load(ctx, file, &pkg)) {
  354. uci_get_errorstr(ctx, &err, file);
  355. ULOG_ERR("unable to load configuration (%s)\n", err);
  356. free(err);
  357. return NULL;
  358. }
  359. return pkg;
  360. }
  361. static int config_load(char *cfg)
  362. {
  363. struct uci_context *ctx = uci_alloc_context();
  364. struct uci_package *pkg = NULL;
  365. struct uci_element *e;
  366. char path[64];
  367. vlist_init(&mounts, avl_strcmp, mounts_update);
  368. if (cfg) {
  369. snprintf(path, sizeof(path), "%s/upper/etc/config/fstab", cfg);
  370. pkg = config_try_load(ctx, path);
  371. if (!pkg) {
  372. snprintf(path, sizeof(path), "%s/etc/config/fstab", cfg);
  373. pkg = config_try_load(ctx, path);
  374. }
  375. }
  376. if (!pkg) {
  377. snprintf(path, sizeof(path), "/etc/config/fstab");
  378. pkg = config_try_load(ctx, path);
  379. }
  380. if (!pkg) {
  381. ULOG_ERR("no usable configuration\n");
  382. return -1;
  383. }
  384. vlist_update(&mounts);
  385. uci_foreach_element(&pkg->sections, e) {
  386. struct uci_section *s = uci_to_section(e);
  387. if (!strcmp(s->type, "mount"))
  388. mount_add(s);
  389. if (!strcmp(s->type, "swap"))
  390. swap_add(s);
  391. if (!strcmp(s->type, "global"))
  392. global_add(s);
  393. }
  394. vlist_flush(&mounts);
  395. return 0;
  396. }
  397. static bool mtdblock_is_nand(char *mtdnum)
  398. {
  399. char tmppath[64];
  400. char buf[16];
  401. FILE *fp;
  402. snprintf(tmppath, sizeof(tmppath) - 1, "/sys/class/mtd/mtd%s/type", mtdnum);
  403. fp = fopen(tmppath, "r");
  404. if (!fp)
  405. return false;
  406. if (!fgets(buf, sizeof(buf), fp)) {
  407. fclose(fp);
  408. return false;
  409. }
  410. fclose(fp);
  411. buf[sizeof(buf) - 1] = '\0'; /* make sure buf is 0-terminated */
  412. buf[strlen(buf) - 1] = '\0'; /* strip final char (newline) */
  413. if (strcmp(buf, "nand"))
  414. return false;
  415. /*
  416. * --- CUT HERE ---
  417. * Keep probing rootfs and rootfs_data in the meantime to not break
  418. * devices using JFFS2 on NAND but only trigger the kernel warnings.
  419. * Remove this once all devices using JFFS2 and squashfs directly on
  420. * NAND have been converted to UBI.
  421. */
  422. snprintf(tmppath, sizeof(tmppath) - 1, "/sys/class/mtd/mtd%s/name", mtdnum);
  423. fp = fopen(tmppath, "r");
  424. if (!fp)
  425. return false;
  426. if (!fgets(buf, sizeof(buf), fp)) {
  427. fclose(fp);
  428. return false;
  429. }
  430. fclose(fp);
  431. buf[sizeof(buf) - 1] = '\0'; /* make sure buf is 0-terminated */
  432. buf[strlen(buf) - 1] = '\0'; /* strip final char (newline) */
  433. /* only return true if name differs from 'rootfs' and 'rootfs_data' */
  434. if (strcmp(buf, "rootfs") && strcmp(buf, "rootfs_data"))
  435. return true;
  436. /* --- CUT HERE --- */
  437. return false;
  438. }
  439. static struct probe_info* _probe_path(char *path)
  440. {
  441. struct probe_info *pr, *epr;
  442. char tmppath[64];
  443. if (!strncmp(path, "/dev/mtdblock", 13) && mtdblock_is_nand(path + 13))
  444. return NULL;
  445. pr = probe_path(path);
  446. if (!pr)
  447. return NULL;
  448. if (path[5] == 'u' && path[6] == 'b' && path[7] == 'i' &&
  449. path[8] >= '0' && path[8] <= '9' ) {
  450. /* skip ubi device if not UBIFS (as it requires ubiblock) */
  451. if (strcmp("ubifs", pr->type))
  452. return NULL;
  453. /* skip ubi device if ubiblock device is present */
  454. snprintf(tmppath, sizeof(tmppath), "/dev/ubiblock%s", path + 8);
  455. list_for_each_entry(epr, &devices, list)
  456. if (!strcmp(epr->dev, tmppath))
  457. return NULL;
  458. }
  459. return pr;
  460. }
  461. static int _cache_load(const char *path)
  462. {
  463. int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
  464. int j;
  465. glob_t gl;
  466. if (glob(path, gl_flags, NULL, &gl) < 0)
  467. return -1;
  468. for (j = 0; j < gl.gl_pathc; j++) {
  469. struct probe_info *pr = _probe_path(gl.gl_pathv[j]);
  470. if (pr)
  471. list_add_tail(&pr->list, &devices);
  472. }
  473. globfree(&gl);
  474. return 0;
  475. }
  476. static void cache_load(int mtd)
  477. {
  478. if (mtd) {
  479. _cache_load("/dev/mtdblock*");
  480. _cache_load("/dev/ubiblock*");
  481. _cache_load("/dev/ubi[0-9]*");
  482. }
  483. _cache_load("/dev/loop*");
  484. _cache_load("/dev/mmcblk*");
  485. _cache_load("/dev/sd*");
  486. _cache_load("/dev/hd*");
  487. _cache_load("/dev/md*");
  488. _cache_load("/dev/nvme*");
  489. _cache_load("/dev/vd*");
  490. _cache_load("/dev/xvd*");
  491. _cache_load("/dev/dm-*");
  492. _cache_load("/dev/fit*");
  493. }
  494. static struct probe_info* find_block_info(char *uuid, char *label, char *path)
  495. {
  496. struct probe_info *pr = NULL;
  497. if (uuid)
  498. list_for_each_entry(pr, &devices, list)
  499. if (pr->uuid && !strcasecmp(pr->uuid, uuid))
  500. return pr;
  501. if (label)
  502. list_for_each_entry(pr, &devices, list)
  503. if (pr->label && !strcmp(pr->label, label))
  504. return pr;
  505. if (path)
  506. list_for_each_entry(pr, &devices, list)
  507. if (pr->dev && !strcmp(basename(pr->dev), basename(path)))
  508. return pr;
  509. return NULL;
  510. }
  511. static char* find_mount_point(char *block)
  512. {
  513. FILE *fp = fopen("/proc/self/mountinfo", "r");
  514. static char line[256];
  515. char *point = NULL, *pos, *tmp, *cpoint, *devname;
  516. struct stat s;
  517. int rstat;
  518. unsigned int minor, major;
  519. if (!fp)
  520. return NULL;
  521. rstat = stat(block, &s);
  522. while (fgets(line, sizeof(line), fp)) {
  523. pos = strchr(line, ' ');
  524. if (!pos)
  525. continue;
  526. pos = strchr(pos + 1, ' ');
  527. if (!pos)
  528. continue;
  529. tmp = ++pos;
  530. pos = strchr(pos, ':');
  531. if (!pos)
  532. continue;
  533. *pos = '\0';
  534. major = atoi(tmp);
  535. tmp = ++pos;
  536. pos = strchr(pos, ' ');
  537. if (!pos)
  538. continue;
  539. *pos = '\0';
  540. minor = atoi(tmp);
  541. pos = strchr(pos + 1, ' ');
  542. if (!pos)
  543. continue;
  544. tmp = ++pos;
  545. pos = strchr(pos, ' ');
  546. if (!pos)
  547. continue;
  548. *pos = '\0';
  549. cpoint = tmp;
  550. pos = strchr(pos + 1, ' ');
  551. if (!pos)
  552. continue;
  553. pos = strchr(pos + 1, ' ');
  554. if (!pos)
  555. continue;
  556. pos = strchr(pos + 1, ' ');
  557. if (!pos)
  558. continue;
  559. tmp = ++pos;
  560. pos = strchr(pos, ' ');
  561. if (!pos)
  562. continue;
  563. *pos = '\0';
  564. devname = tmp;
  565. if (!strcmp(block, devname)) {
  566. point = strdup(cpoint);
  567. break;
  568. }
  569. if (rstat)
  570. continue;
  571. if (!S_ISBLK(s.st_mode))
  572. continue;
  573. if (major == major(s.st_rdev) &&
  574. minor == minor(s.st_rdev)) {
  575. point = strdup(cpoint);
  576. break;
  577. }
  578. }
  579. fclose(fp);
  580. return point;
  581. }
  582. static int print_block_uci(struct probe_info *pr)
  583. {
  584. if (!strcmp(pr->type, "swap")) {
  585. printf("config 'swap'\n");
  586. } else {
  587. char *mp = find_mount_point(pr->dev);
  588. printf("config 'mount'\n");
  589. if (mp) {
  590. printf("\toption\ttarget\t'%s'\n", mp);
  591. free(mp);
  592. } else {
  593. printf("\toption\ttarget\t'/mnt/%s'\n", basename(pr->dev));
  594. }
  595. }
  596. if (pr->uuid)
  597. printf("\toption\tuuid\t'%s'\n", pr->uuid);
  598. else
  599. printf("\toption\tdevice\t'%s'\n", pr->dev);
  600. printf("\toption\tenabled\t'0'\n\n");
  601. return 0;
  602. }
  603. static int print_block_info(struct probe_info *pr)
  604. {
  605. static char *mp;
  606. mp = find_mount_point(pr->dev);
  607. printf("%s:", pr->dev);
  608. if (pr->uuid)
  609. printf(" UUID=\"%s\"", pr->uuid);
  610. if (pr->label)
  611. printf(" LABEL=\"%s\"", pr->label);
  612. if (pr->version)
  613. printf(" VERSION=\"%s\"", pr->version);
  614. if (mp) {
  615. printf(" MOUNT=\"%s\"", mp);
  616. free(mp);
  617. }
  618. printf(" TYPE=\"%s\"\n", pr->type);
  619. return 0;
  620. }
  621. static void check_filesystem(struct probe_info *pr)
  622. {
  623. pid_t pid;
  624. struct stat statbuf;
  625. const char *e2fsck = "/usr/sbin/e2fsck";
  626. const char *f2fsck = "/usr/sbin/fsck.f2fs";
  627. const char *fatfsck = "/usr/sbin/fsck.fat";
  628. const char *btrfsck = "/usr/bin/btrfsck";
  629. const char *ntfsck = "/usr/bin/ntfsfix";
  630. const char *ckfs;
  631. /* UBIFS does not need stuff like fsck */
  632. if (!strncmp(pr->type, "ubifs", 5))
  633. return;
  634. if (!strncmp(pr->type, "vfat", 4)) {
  635. ckfs = fatfsck;
  636. } else if (!strncmp(pr->type, "f2fs", 4)) {
  637. ckfs = f2fsck;
  638. } else if (!strncmp(pr->type, "ext", 3)) {
  639. ckfs = e2fsck;
  640. } else if (!strncmp(pr->type, "btrfs", 5)) {
  641. ckfs = btrfsck;
  642. } else if (!strncmp(pr->type, "ntfs", 4)) {
  643. ckfs = ntfsck;
  644. } else {
  645. ULOG_ERR("check_filesystem: %s is not supported\n", pr->type);
  646. return;
  647. }
  648. if (stat(ckfs, &statbuf) < 0) {
  649. ULOG_ERR("check_filesystem: %s not found\n", ckfs);
  650. return;
  651. }
  652. pid = fork();
  653. if (!pid) {
  654. if(!strncmp(pr->type, "f2fs", 4)) {
  655. execl(ckfs, ckfs, "-f", pr->dev, NULL);
  656. exit(EXIT_FAILURE);
  657. } else if(!strncmp(pr->type, "btrfs", 5)) {
  658. execl(ckfs, ckfs, "--repair", pr->dev, NULL);
  659. exit(EXIT_FAILURE);
  660. } else if(!strncmp(pr->type, "ntfs", 4)) {
  661. execl(ckfs, ckfs, "-b", pr->dev, NULL);
  662. exit(EXIT_FAILURE);
  663. } else {
  664. execl(ckfs, ckfs, "-p", pr->dev, NULL);
  665. exit(EXIT_FAILURE);
  666. }
  667. } else if (pid > 0) {
  668. int status;
  669. waitpid(pid, &status, 0);
  670. if (WIFEXITED(status) && WEXITSTATUS(status))
  671. ULOG_ERR("check_filesystem: %s returned %d\n", ckfs, WEXITSTATUS(status));
  672. if (WIFSIGNALED(status))
  673. ULOG_ERR("check_filesystem: %s terminated by %s\n", ckfs, strsignal(WTERMSIG(status)));
  674. }
  675. }
  676. static void handle_swapfiles(bool on)
  677. {
  678. struct stat s;
  679. struct mount *m;
  680. struct probe_info *pr;
  681. vlist_for_each_element(&mounts, m, node)
  682. {
  683. if (m->type != TYPE_SWAP || !m->target)
  684. continue;
  685. if (stat(m->target, &s) || !S_ISREG(s.st_mode))
  686. continue;
  687. pr = _probe_path(m->target);
  688. if (!pr)
  689. continue;
  690. if (!strcmp(pr->type, "swap")) {
  691. if (on)
  692. swapon(pr->dev, m->prio);
  693. else
  694. swapoff(pr->dev);
  695. }
  696. free(pr);
  697. }
  698. }
  699. static void to_devnull(int fd)
  700. {
  701. int devnull = open("/dev/null", fd ? O_WRONLY : O_RDONLY);
  702. if (devnull >= 0)
  703. dup2(devnull, fd);
  704. if (devnull > STDERR_FILENO)
  705. close(devnull);
  706. }
  707. static int exec_mount(const char *source, const char *target,
  708. const char *fstype, const char *options)
  709. {
  710. pid_t pid;
  711. struct stat s;
  712. FILE *mount_fd;
  713. int err, status, pfds[2];
  714. char errmsg[128], cmd[sizeof("/sbin/mount.XXXXXXXXXXXXXXXX\0")];
  715. snprintf(cmd, sizeof(cmd), "/sbin/mount.%s", fstype);
  716. if (stat(cmd, &s) < 0 || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR)) {
  717. ULOG_ERR("No \"mount.%s\" utility available\n", fstype);
  718. return -1;
  719. }
  720. if (pipe(pfds) < 0)
  721. return -1;
  722. fcntl(pfds[0], F_SETFD, fcntl(pfds[0], F_GETFD) | FD_CLOEXEC);
  723. fcntl(pfds[1], F_SETFD, fcntl(pfds[1], F_GETFD) | FD_CLOEXEC);
  724. pid = vfork();
  725. switch (pid) {
  726. case -1:
  727. close(pfds[0]);
  728. close(pfds[1]);
  729. return -1;
  730. case 0:
  731. to_devnull(STDIN_FILENO);
  732. to_devnull(STDOUT_FILENO);
  733. dup2(pfds[1], STDERR_FILENO);
  734. close(pfds[0]);
  735. close(pfds[1]);
  736. if (options && *options)
  737. execl(cmd, cmd, "-o", options, source, target, NULL);
  738. else
  739. execl(cmd, cmd, source, target, NULL);
  740. return -1;
  741. default:
  742. close(pfds[1]);
  743. mount_fd = fdopen(pfds[0], "r");
  744. while (fgets(errmsg, sizeof(errmsg), mount_fd))
  745. ULOG_ERR("mount.%s: %s", fstype, errmsg);
  746. fclose(mount_fd);
  747. err = waitpid(pid, &status, 0);
  748. if (err != -1) {
  749. if (status != 0) {
  750. ULOG_ERR("mount.%s: failed with status %d\n", fstype, status);
  751. errno = EINVAL;
  752. err = -1;
  753. } else {
  754. errno = 0;
  755. err = 0;
  756. }
  757. }
  758. break;
  759. }
  760. return err;
  761. }
  762. static const char * const ntfs_fs[] = { "ntfs3", "ntfs-3g", "antfs", "ntfs" };
  763. static int handle_mount(const char *source, const char *target,
  764. const char *fstype, struct mount *m)
  765. {
  766. size_t mount_opts_len;
  767. char *mount_opts = NULL, *ptr;
  768. const char * const *filesystems;
  769. int err = -EINVAL;
  770. size_t count;
  771. int i;
  772. if (!strcmp(fstype, "ntfs")) {
  773. filesystems = ntfs_fs;
  774. count = ARRAY_SIZE(ntfs_fs);
  775. } else {
  776. filesystems = &fstype;
  777. count = 1;
  778. }
  779. for (i = 0; i < count; i++) {
  780. const char *fs = filesystems[i];
  781. err = mount(source, target, fs, m ? m->flags : 0,
  782. (m && m->options) ? m->options : "");
  783. if (!err || errno != ENODEV)
  784. break;
  785. }
  786. /* Requested file system type is not available in kernel,
  787. attempt to call mount helper. */
  788. if (err == -1 && errno == ENODEV) {
  789. if (m) {
  790. /* Convert mount flags back into string representation,
  791. first calculate needed length of string buffer... */
  792. mount_opts_len = 1 + (m->options ? strlen(m->options) : 0);
  793. for (i = 0; i < ARRAY_SIZE(mount_flags); i++)
  794. if ((mount_flags[i].flag > 0) &&
  795. (mount_flags[i].flag < INT_MAX) &&
  796. (m->flags & (uint32_t)mount_flags[i].flag))
  797. mount_opts_len += strlen(mount_flags[i].name) + 1;
  798. /* ... then now allocate and fill it ... */
  799. ptr = mount_opts = calloc(1, mount_opts_len);
  800. if (!ptr) {
  801. errno = ENOMEM;
  802. return -1;
  803. }
  804. if (m->options)
  805. ptr += sprintf(ptr, "%s,", m->options);
  806. for (i = 0; i < ARRAY_SIZE(mount_flags); i++)
  807. if ((mount_flags[i].flag > 0) &&
  808. (mount_flags[i].flag < INT_MAX) &&
  809. (m->flags & (uint32_t)mount_flags[i].flag))
  810. ptr += sprintf(ptr, "%s,", mount_flags[i].name);
  811. mount_opts[mount_opts_len - 1] = 0;
  812. }
  813. /* ... and now finally invoke the external mount program */
  814. for (i = 0; i < count; i++) {
  815. const char *fs = filesystems[i];
  816. err = exec_mount(source, target, fs, mount_opts);
  817. if (!err)
  818. break;
  819. }
  820. }
  821. free(mount_opts);
  822. return err;
  823. }
  824. static int blockd_notify(const char *method, char *device, struct mount *m,
  825. struct probe_info *pr)
  826. {
  827. struct ubus_context *ctx = ubus_connect(NULL);
  828. uint32_t id;
  829. int err;
  830. if (!ctx)
  831. return -ENXIO;
  832. if (!ubus_lookup_id(ctx, "block", &id)) {
  833. struct blob_buf buf = { 0 };
  834. char *d = strrchr(device, '/');
  835. if (d)
  836. d++;
  837. else
  838. d = device;
  839. blob_buf_init(&buf, 0);
  840. if (m) {
  841. blobmsg_add_string(&buf, "device", d);
  842. if (m->uuid)
  843. blobmsg_add_string(&buf, "uuid", m->uuid);
  844. if (m->label)
  845. blobmsg_add_string(&buf, "label", m->label);
  846. if (m->target)
  847. blobmsg_add_string(&buf, "target", m->target);
  848. if (m->options)
  849. blobmsg_add_string(&buf, "options", m->options);
  850. if (m->autofs)
  851. blobmsg_add_u32(&buf, "autofs", m->autofs);
  852. if (pr->type)
  853. blobmsg_add_string(&buf, "type", pr->type);
  854. if (pr->version)
  855. blobmsg_add_string(&buf, "version", pr->version);
  856. } else if (pr) {
  857. blobmsg_add_string(&buf, "device", d);
  858. if (pr->uuid)
  859. blobmsg_add_string(&buf, "uuid", pr->uuid);
  860. if (pr->label)
  861. blobmsg_add_string(&buf, "label", pr->label);
  862. if (pr->type)
  863. blobmsg_add_string(&buf, "type", pr->type);
  864. if (pr->version)
  865. blobmsg_add_string(&buf, "version", pr->version);
  866. blobmsg_add_u32(&buf, "anon", 1);
  867. } else {
  868. blobmsg_add_string(&buf, "device", d);
  869. blobmsg_add_u32(&buf, "remove", 1);
  870. }
  871. err = ubus_invoke(ctx, id, method, buf.head, NULL, NULL, 3000);
  872. } else {
  873. err = -ENOENT;
  874. }
  875. ubus_free(ctx);
  876. return err;
  877. }
  878. static int mount_device(struct probe_info *pr, int type)
  879. {
  880. struct mount *m;
  881. struct stat st;
  882. char *_target = NULL;
  883. char *target;
  884. char *device;
  885. char *mp;
  886. int err;
  887. if (!pr)
  888. return -1;
  889. device = basename(pr->dev);
  890. if (!strcmp(pr->type, "swap")) {
  891. if ((type == TYPE_HOTPLUG) && !auto_swap)
  892. return -1;
  893. m = find_swap(pr->uuid, pr->label, device);
  894. if (m || anon_swap)
  895. swapon(pr->dev, (m) ? (m->prio) : (0));
  896. return 0;
  897. }
  898. m = find_block(pr->uuid, pr->label, device, NULL);
  899. if (m && m->extroot)
  900. return -1;
  901. mp = find_mount_point(pr->dev);
  902. if (mp) {
  903. if (m && m->type == TYPE_MOUNT && m->target && strcmp(m->target, mp)) {
  904. ULOG_ERR("%s is already mounted on %s\n", pr->dev, mp);
  905. err = -1;
  906. } else
  907. err = 0;
  908. free(mp);
  909. return err;
  910. }
  911. if (type == TYPE_HOTPLUG)
  912. blockd_notify("hotplug", device, m, pr);
  913. /* Check if device should be mounted & set the target directory */
  914. if (m) {
  915. switch (type) {
  916. case TYPE_HOTPLUG:
  917. if (m->autofs)
  918. return 0;
  919. if (!auto_mount)
  920. return -1;
  921. break;
  922. case TYPE_AUTOFS:
  923. if (!m->autofs)
  924. return -1;
  925. break;
  926. case TYPE_DEV:
  927. if (m->autofs)
  928. return -1;
  929. break;
  930. }
  931. if (m->autofs) {
  932. if (asprintf(&_target, "/tmp/run/blockd/%s", device) == -1)
  933. exit(ENOMEM);
  934. target = _target;
  935. } else if (m->target) {
  936. target = m->target;
  937. } else {
  938. if (asprintf(&_target, "/mnt/%s", device) == -1)
  939. exit(ENOMEM);
  940. target = _target;
  941. }
  942. } else if (anon_mount) {
  943. if (asprintf(&_target, "/mnt/%s", device) == -1)
  944. exit(ENOMEM);
  945. target = _target;
  946. } else {
  947. /* No reason to mount this device */
  948. return 0;
  949. }
  950. /* Mount the device */
  951. if (check_fs)
  952. check_filesystem(pr);
  953. mkdir_p(target, 0755);
  954. if (!lstat(target, &st) && S_ISLNK(st.st_mode))
  955. unlink(target);
  956. err = handle_mount(pr->dev, target, pr->type, m);
  957. if (err) {
  958. ULOG_ERR("mounting %s (%s) as %s failed (%d) - %m\n",
  959. pr->dev, pr->type, target, errno);
  960. if (_target)
  961. free(_target);
  962. return err;
  963. }
  964. if (_target)
  965. free(_target);
  966. handle_swapfiles(true);
  967. if (type != TYPE_AUTOFS)
  968. blockd_notify("mount", device, NULL, NULL);
  969. return 0;
  970. }
  971. static int umount_device(char *path, int type, bool all)
  972. {
  973. char *mp, *devpath;
  974. int err;
  975. if (strlen(path) > 5 && !strncmp("/dev/", path, 5)) {
  976. mp = find_mount_point(path);
  977. } else {
  978. devpath = malloc(strlen(path) + 6);
  979. strcpy(devpath, "/dev/");
  980. strcat(devpath, path);
  981. mp = find_mount_point(devpath);
  982. free(devpath);
  983. }
  984. if (!mp)
  985. return -1;
  986. if (!strcmp(mp, "/") && !all) {
  987. free(mp);
  988. return 0;
  989. }
  990. if (type != TYPE_AUTOFS)
  991. blockd_notify("umount", basename(path), NULL, NULL);
  992. err = umount2(mp, MNT_DETACH);
  993. if (err) {
  994. ULOG_ERR("unmounting %s (%s) failed (%d) - %m\n", path, mp,
  995. errno);
  996. } else {
  997. ULOG_INFO("unmounted %s (%s)\n", path, mp);
  998. rmdir(mp);
  999. }
  1000. free(mp);
  1001. return err;
  1002. }
  1003. static int mount_action(char *action, char *device, int type)
  1004. {
  1005. char *path = NULL;
  1006. struct probe_info *pr;
  1007. if (!action || !device)
  1008. return -1;
  1009. if (!strcmp(action, "remove")) {
  1010. if (type == TYPE_HOTPLUG)
  1011. blockd_notify("hotplug", device, NULL, NULL);
  1012. umount_device(device, type, true);
  1013. return 0;
  1014. } else if (strcmp(action, "add")) {
  1015. ULOG_ERR("Unkown action %s\n", action);
  1016. return -1;
  1017. }
  1018. if (config_load(NULL))
  1019. return -1;
  1020. cache_load(1);
  1021. list_for_each_entry(pr, &devices, list)
  1022. if (!strcmp(basename(pr->dev), device))
  1023. path = pr->dev;
  1024. if (!path)
  1025. return -1;
  1026. return mount_device(find_block_info(NULL, NULL, path), type);
  1027. }
  1028. static int main_hotplug(int argc, char **argv)
  1029. {
  1030. return mount_action(getenv("ACTION"), getenv("DEVNAME"), TYPE_HOTPLUG);
  1031. }
  1032. static int main_autofs(int argc, char **argv)
  1033. {
  1034. int err = 0;
  1035. if (argc < 3)
  1036. return -1;
  1037. if (!strcmp(argv[2], "start")) {
  1038. struct probe_info *pr;
  1039. if (config_load(NULL))
  1040. return -1;
  1041. cache_load(1);
  1042. list_for_each_entry(pr, &devices, list) {
  1043. struct mount *m;
  1044. char *mp;
  1045. if (!strcmp(pr->type, "swap"))
  1046. continue;
  1047. m = find_block(pr->uuid, pr->label, NULL, NULL);
  1048. if (m && m->extroot)
  1049. continue;
  1050. blockd_notify("hotplug", pr->dev, m, pr);
  1051. if ((!m || !m->autofs) && (mp = find_mount_point(pr->dev))) {
  1052. blockd_notify("mount", pr->dev, NULL, NULL);
  1053. free(mp);
  1054. }
  1055. }
  1056. } else {
  1057. if (argc < 4)
  1058. return -EINVAL;
  1059. err = mount_action(argv[2], argv[3], TYPE_AUTOFS);
  1060. }
  1061. if (err) {
  1062. ULOG_ERR("autofs: \"%s\" action has failed: %d\n", argv[2], err);
  1063. }
  1064. return err;
  1065. }
  1066. static int find_block_mtd(char *name, char *part, int plen)
  1067. {
  1068. FILE *fp = fopen("/proc/mtd", "r");
  1069. static char line[256];
  1070. char *index = NULL;
  1071. if(!fp)
  1072. return -1;
  1073. while (!index && fgets(line, sizeof(line), fp)) {
  1074. if (strstr(line, name)) {
  1075. char *eol = strstr(line, ":");
  1076. if (!eol)
  1077. continue;
  1078. *eol = '\0';
  1079. index = &line[3];
  1080. }
  1081. }
  1082. fclose(fp);
  1083. if (!index)
  1084. return -1;
  1085. snprintf(part, plen, "/dev/mtdblock%s", index);
  1086. return 0;
  1087. }
  1088. #ifdef UBIFS_EXTROOT
  1089. static int find_ubi_vol(libubi_t libubi, char *name, int *dev_num, int *vol_id)
  1090. {
  1091. int dev = 0;
  1092. while (ubi_dev_present(libubi, dev))
  1093. {
  1094. struct ubi_dev_info dev_info;
  1095. struct ubi_vol_info vol_info;
  1096. if (ubi_get_dev_info1(libubi, dev++, &dev_info))
  1097. continue;
  1098. if (ubi_get_vol_info1_nm(libubi, dev_info.dev_num, name, &vol_info))
  1099. continue;
  1100. *dev_num = dev_info.dev_num;
  1101. *vol_id = vol_info.vol_id;
  1102. return 0;
  1103. }
  1104. return -1;
  1105. }
  1106. static int find_block_ubi(libubi_t libubi, char *name, char *part, int plen)
  1107. {
  1108. int dev_num;
  1109. int vol_id;
  1110. int err = -1;
  1111. err = find_ubi_vol(libubi, name, &dev_num, &vol_id);
  1112. if (!err)
  1113. snprintf(part, plen, "/dev/ubi%d_%d", dev_num, vol_id);
  1114. return err;
  1115. }
  1116. static int find_block_ubi_RO(libubi_t libubi, char *name, char *part, int plen)
  1117. {
  1118. int dev_num;
  1119. int vol_id;
  1120. int err = -1;
  1121. err = find_ubi_vol(libubi, name, &dev_num, &vol_id);
  1122. if (!err)
  1123. snprintf(part, plen, "/dev/ubiblock%d_%d", dev_num, vol_id);
  1124. return err;
  1125. }
  1126. #endif
  1127. static int find_dev(const char *path, char *buf, int len)
  1128. {
  1129. DIR *d;
  1130. dev_t root;
  1131. struct stat s;
  1132. struct dirent *e;
  1133. if (stat(path, &s))
  1134. return -1;
  1135. if (!(d = opendir("/dev")))
  1136. return -1;
  1137. root = s.st_dev;
  1138. while ((e = readdir(d)) != NULL) {
  1139. snprintf(buf, len, "/dev/%s", e->d_name);
  1140. if (stat(buf, &s) || s.st_rdev != root)
  1141. continue;
  1142. closedir(d);
  1143. return 0;
  1144. }
  1145. closedir(d);
  1146. return -1;
  1147. }
  1148. static int find_root_dev(char *buf, int len)
  1149. {
  1150. int err = find_dev("/", buf, len);
  1151. if (err)
  1152. err = find_dev("/rom", buf, len);
  1153. return err;
  1154. }
  1155. static int test_fs_support(const char *name)
  1156. {
  1157. char line[128], *p;
  1158. int rv = -1;
  1159. FILE *f;
  1160. if ((f = fopen("/proc/filesystems", "r")) != NULL) {
  1161. while (fgets(line, sizeof(line), f)) {
  1162. p = strtok(line, "\t\n");
  1163. if (p && !strcmp(p, "nodev"))
  1164. p = strtok(NULL, "\t\n");
  1165. if (p && !strcmp(p, name)) {
  1166. rv = 0;
  1167. break;
  1168. }
  1169. }
  1170. fclose(f);
  1171. }
  1172. return rv;
  1173. }
  1174. /**
  1175. * Check if mounted partition is a valid extroot
  1176. *
  1177. * @path target mount point
  1178. *
  1179. * Valid extroot partition has to contain /etc/.extroot-uuid with UUID of root
  1180. * device. This function reads UUID and verifies it OR writes UUID to
  1181. * .extroot-uuid if it doesn't exist yet (first extroot usage).
  1182. */
  1183. static int check_extroot(char *path)
  1184. {
  1185. struct probe_info *pr = NULL;
  1186. struct probe_info *tmp;
  1187. struct stat s;
  1188. char uuid[64] = { 0 };
  1189. char devpath[32];
  1190. char tag[64];
  1191. FILE *fp;
  1192. int err;
  1193. snprintf(tag, sizeof(tag), "%s/etc/.extroot-default", path);
  1194. if (stat(tag, &s))
  1195. return 0;
  1196. err = find_root_dev(devpath, sizeof(devpath));
  1197. if (err)
  1198. err = find_block_mtd("\"rootfs\"", devpath, sizeof(devpath));
  1199. #ifdef UBIFS_EXTROOT
  1200. if (err) {
  1201. libubi_t libubi;
  1202. libubi = libubi_open();
  1203. err = find_block_ubi_RO(libubi, "rootfs", devpath, sizeof(devpath));
  1204. libubi_close(libubi);
  1205. }
  1206. #endif
  1207. if (err) {
  1208. ULOG_ERR("extroot: unable to determine root device\n");
  1209. return -1;
  1210. }
  1211. /* Find root device probe_info so we know its UUID */
  1212. list_for_each_entry(tmp, &devices, list) {
  1213. if (!strcmp(tmp->dev, devpath)) {
  1214. pr = tmp;
  1215. break;
  1216. }
  1217. }
  1218. if (!pr) {
  1219. ULOG_ERR("extroot: unable to lookup root device %s\n", devpath);
  1220. return -1;
  1221. }
  1222. snprintf(tag, sizeof(tag), "%s/etc", path);
  1223. if (stat(tag, &s))
  1224. mkdir_p(tag, 0755);
  1225. snprintf(tag, sizeof(tag), "%s/etc/.extroot-uuid", path);
  1226. if (stat(tag, &s)) {
  1227. fp = fopen(tag, "w+");
  1228. if (!fp) {
  1229. ULOG_ERR("extroot: failed to write UUID to %s: %d (%m)\n",
  1230. tag, errno);
  1231. /* return 0 to continue boot regardless of error */
  1232. return 0;
  1233. }
  1234. fputs(pr->uuid, fp);
  1235. fclose(fp);
  1236. return 0;
  1237. }
  1238. fp = fopen(tag, "r");
  1239. if (!fp) {
  1240. ULOG_ERR("extroot: failed to read UUID from %s: %d (%m)\n", tag,
  1241. errno);
  1242. return -1;
  1243. }
  1244. if (!fgets(uuid, sizeof(uuid), fp))
  1245. ULOG_ERR("extroot: failed to read UUID from %s: %d (%m)\n", tag,
  1246. errno);
  1247. fclose(fp);
  1248. if (*uuid && !strcasecmp(uuid, pr->uuid))
  1249. return 0;
  1250. ULOG_ERR("extroot: UUID mismatch (root: %s, %s: %s)\n", pr->uuid,
  1251. basename(path), uuid);
  1252. return -1;
  1253. }
  1254. /*
  1255. * Read info about extroot from UCI (using prefix) and mount it.
  1256. */
  1257. static int mount_extroot(char *cfg)
  1258. {
  1259. char overlay[] = "/tmp/extroot/overlay";
  1260. char mnt[] = "/tmp/extroot/mnt";
  1261. char *path = mnt;
  1262. struct probe_info *pr;
  1263. struct mount *m;
  1264. int err = -1;
  1265. /* Load @cfg/etc/config/fstab */
  1266. if (config_load(cfg))
  1267. return -2;
  1268. /* See if there is extroot-specific mount config */
  1269. m = find_block(NULL, NULL, NULL, "/");
  1270. if (!m)
  1271. m = find_block(NULL, NULL, NULL, "/overlay");
  1272. if (!m || !m->extroot)
  1273. {
  1274. ULOG_INFO("extroot: not configured\n");
  1275. return -1;
  1276. }
  1277. /* Find block device pointed by the mount config */
  1278. pr = find_block_info(m->uuid, m->label, m->device);
  1279. if (!pr && delay_root){
  1280. ULOG_INFO("extroot: device not present, retrying in %u seconds\n", delay_root);
  1281. sleep(delay_root);
  1282. make_devs();
  1283. cache_load(1);
  1284. pr = find_block_info(m->uuid, m->label, m->device);
  1285. }
  1286. if (pr) {
  1287. if (strncmp(pr->type, "ext", 3) &&
  1288. strncmp(pr->type, "f2fs", 4) &&
  1289. strncmp(pr->type, "btrfs", 5) &&
  1290. strncmp(pr->type, "ntfs", 4) &&
  1291. strncmp(pr->type, "ubifs", 5)) {
  1292. ULOG_ERR("extroot: unsupported filesystem %s, try ext4, f2fs, btrfs, ntfs or ubifs\n", pr->type);
  1293. return -1;
  1294. }
  1295. if (test_fs_support(pr->type)) {
  1296. ULOG_ERR("extroot: filesystem %s not supported by kernel\n", pr->type);
  1297. return -1;
  1298. }
  1299. if (m->overlay)
  1300. path = overlay;
  1301. mkdir_p(path, 0755);
  1302. if (check_fs)
  1303. check_filesystem(pr);
  1304. err = mount(pr->dev, path, pr->type, m->flags,
  1305. (m->options) ? (m->options) : (""));
  1306. if (err) {
  1307. ULOG_ERR("extroot: mounting %s (%s) on %s failed: %d (%m)\n",
  1308. pr->dev, pr->type, path, errno);
  1309. } else if (m->overlay) {
  1310. err = check_extroot(path);
  1311. if (err)
  1312. umount(path);
  1313. }
  1314. } else {
  1315. ULOG_ERR("extroot: cannot find device %s%s\n",
  1316. (m->uuid ? "with UUID " : (m->label ? "with label " : "")),
  1317. (m->uuid ? m->uuid : (m->label ? m->label : m->device)));
  1318. }
  1319. return err;
  1320. }
  1321. /**
  1322. * Look for extroot config and mount it if present
  1323. *
  1324. * Look for /etc/config/fstab on all supported partitions and use it for
  1325. * mounting extroot if specified.
  1326. */
  1327. static int main_extroot(int argc, char **argv)
  1328. {
  1329. struct probe_info *pr;
  1330. char blkdev_path[32] = { 0 };
  1331. int err = -1;
  1332. #ifdef UBIFS_EXTROOT
  1333. libubi_t libubi;
  1334. #endif
  1335. if (!getenv("PREINIT"))
  1336. return -1;
  1337. if (argc != 2) {
  1338. ULOG_ERR("Usage: block extroot\n");
  1339. return -1;
  1340. }
  1341. make_devs();
  1342. cache_load(1);
  1343. /* enable LOG_INFO messages */
  1344. ulog_threshold(LOG_INFO);
  1345. /* try the currently mounted overlay if exists */
  1346. err = mount_extroot("/tmp/overlay");
  1347. if (!err)
  1348. return err;
  1349. /*
  1350. * Look for "rootfs_data". We will want to mount it and check for
  1351. * extroot configuration.
  1352. */
  1353. /* Start with looking for MTD partition */
  1354. find_block_mtd("\"rootfs_data\"", blkdev_path, sizeof(blkdev_path));
  1355. if (blkdev_path[0]) {
  1356. pr = find_block_info(NULL, NULL, blkdev_path);
  1357. if (pr && !strcmp(pr->type, "jffs2")) {
  1358. char cfg[] = "/tmp/jffs_cfg";
  1359. /*
  1360. * Mount MTD part and try extroot (using
  1361. * /etc/config/fstab from that partition)
  1362. */
  1363. mkdir_p(cfg, 0755);
  1364. if (!mount(blkdev_path, cfg, "jffs2", MS_NOATIME, NULL)) {
  1365. err = mount_extroot(cfg);
  1366. umount2(cfg, MNT_DETACH);
  1367. }
  1368. if (err < 0)
  1369. rmdir("/tmp/overlay");
  1370. rmdir(cfg);
  1371. return err;
  1372. }
  1373. }
  1374. #ifdef UBIFS_EXTROOT
  1375. /* ... but it also could be an UBI volume */
  1376. memset(blkdev_path, 0, sizeof(blkdev_path));
  1377. libubi = libubi_open();
  1378. find_block_ubi(libubi, "rootfs_data", blkdev_path, sizeof(blkdev_path));
  1379. libubi_close(libubi);
  1380. if (blkdev_path[0]) {
  1381. char cfg[] = "/tmp/ubifs_cfg";
  1382. /* Mount volume and try extroot (using fstab from that vol) */
  1383. mkdir_p(cfg, 0755);
  1384. if (!mount(blkdev_path, cfg, "ubifs", MS_NOATIME, NULL)) {
  1385. err = mount_extroot(cfg);
  1386. umount2(cfg, MNT_DETACH);
  1387. }
  1388. if (err < 0)
  1389. rmdir("/tmp/overlay");
  1390. rmdir(cfg);
  1391. return err;
  1392. }
  1393. #endif
  1394. /* As a last resort look for /etc/config/fstab on "rootfs" partition */
  1395. return mount_extroot(NULL);
  1396. }
  1397. static int main_mount(int argc, char **argv)
  1398. {
  1399. struct probe_info *pr;
  1400. if (config_load(NULL))
  1401. return -1;
  1402. cache_load(1);
  1403. list_for_each_entry(pr, &devices, list)
  1404. mount_device(pr, TYPE_DEV);
  1405. handle_swapfiles(true);
  1406. return 0;
  1407. }
  1408. static int main_umount(int argc, char **argv)
  1409. {
  1410. struct probe_info *pr;
  1411. bool all = false;
  1412. if (config_load(NULL))
  1413. return -1;
  1414. handle_swapfiles(false);
  1415. cache_load(1);
  1416. if (argc == 3)
  1417. all = !strcmp(argv[2], "-a");
  1418. list_for_each_entry(pr, &devices, list) {
  1419. struct mount *m;
  1420. if (!strcmp(pr->type, "swap"))
  1421. continue;
  1422. m = find_block(pr->uuid, pr->label, basename(pr->dev), NULL);
  1423. if (m && m->extroot)
  1424. continue;
  1425. umount_device(pr->dev, TYPE_DEV, all);
  1426. }
  1427. return 0;
  1428. }
  1429. static int main_detect(int argc, char **argv)
  1430. {
  1431. struct probe_info *pr;
  1432. cache_load(0);
  1433. printf("config 'global'\n");
  1434. printf("\toption\tanon_swap\t'0'\n");
  1435. printf("\toption\tanon_mount\t'0'\n");
  1436. printf("\toption\tauto_swap\t'1'\n");
  1437. printf("\toption\tauto_mount\t'1'\n");
  1438. printf("\toption\tdelay_root\t'5'\n");
  1439. printf("\toption\tcheck_fs\t'0'\n\n");
  1440. list_for_each_entry(pr, &devices, list)
  1441. print_block_uci(pr);
  1442. return 0;
  1443. }
  1444. static int main_info(int argc, char **argv)
  1445. {
  1446. int i;
  1447. struct probe_info *pr;
  1448. cache_load(1);
  1449. if (argc == 2) {
  1450. list_for_each_entry(pr, &devices, list)
  1451. print_block_info(pr);
  1452. return 0;
  1453. };
  1454. for (i = 2; i < argc; i++) {
  1455. struct stat s;
  1456. if (stat(argv[i], &s)) {
  1457. ULOG_ERR("failed to stat %s\n", argv[i]);
  1458. continue;
  1459. }
  1460. if (!S_ISBLK(s.st_mode) && !(S_ISCHR(s.st_mode) && major(s.st_rdev) == 250)) {
  1461. ULOG_ERR("%s is not a block device\n", argv[i]);
  1462. continue;
  1463. }
  1464. pr = find_block_info(NULL, NULL, argv[i]);
  1465. if (pr)
  1466. print_block_info(pr);
  1467. }
  1468. return 0;
  1469. }
  1470. static int swapon_usage(void)
  1471. {
  1472. fprintf(stderr, "Usage: swapon [-s] [-a] [[-p pri] DEVICE]\n\n"
  1473. "\tStart swapping on [DEVICE]\n"
  1474. " -a\tStart swapping on all swap devices\n"
  1475. " -p pri\tSet priority of swap device\n"
  1476. " -s\tShow summary\n");
  1477. return -1;
  1478. }
  1479. static int main_swapon(int argc, char **argv)
  1480. {
  1481. int ch;
  1482. FILE *fp;
  1483. char *lineptr;
  1484. size_t s;
  1485. struct probe_info *pr;
  1486. int flags = 0;
  1487. int pri;
  1488. struct stat st;
  1489. int err;
  1490. while ((ch = getopt(argc, argv, "ap:s")) != -1) {
  1491. switch(ch) {
  1492. case 's':
  1493. fp = fopen("/proc/swaps", "r");
  1494. lineptr = NULL;
  1495. if (!fp) {
  1496. ULOG_ERR("failed to open /proc/swaps\n");
  1497. return -1;
  1498. }
  1499. while (getline(&lineptr, &s, fp) > 0)
  1500. printf("%s", lineptr);
  1501. if (lineptr)
  1502. free(lineptr);
  1503. fclose(fp);
  1504. return 0;
  1505. case 'a':
  1506. cache_load(0);
  1507. list_for_each_entry(pr, &devices, list) {
  1508. if (strcmp(pr->type, "swap"))
  1509. continue;
  1510. if (swapon(pr->dev, 0))
  1511. ULOG_ERR("failed to swapon %s\n", pr->dev);
  1512. }
  1513. return 0;
  1514. case 'p':
  1515. pri = atoi(optarg);
  1516. if (pri >= 0)
  1517. flags = ((pri << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER;
  1518. break;
  1519. default:
  1520. return swapon_usage();
  1521. }
  1522. }
  1523. if (optind != (argc - 1))
  1524. return swapon_usage();
  1525. if (stat(argv[optind], &st) || (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode))) {
  1526. ULOG_ERR("%s is not a block device or file\n", argv[optind]);
  1527. return -1;
  1528. }
  1529. err = swapon(argv[optind], flags);
  1530. if (err) {
  1531. ULOG_ERR("failed to swapon %s (%d)\n", argv[optind], err);
  1532. return err;
  1533. }
  1534. return 0;
  1535. }
  1536. static int main_swapoff(int argc, char **argv)
  1537. {
  1538. if (argc != 2) {
  1539. ULOG_ERR("Usage: swapoff [-a] [DEVICE]\n\n"
  1540. "\tStop swapping on DEVICE\n"
  1541. " -a\tStop swapping on all swap devices\n");
  1542. return -1;
  1543. }
  1544. if (!strcmp(argv[1], "-a")) {
  1545. FILE *fp = fopen("/proc/swaps", "r");
  1546. char line[256];
  1547. if (!fp) {
  1548. ULOG_ERR("failed to open /proc/swaps\n");
  1549. return -1;
  1550. }
  1551. if (fgets(line, sizeof(line), fp))
  1552. while (fgets(line, sizeof(line), fp)) {
  1553. char *end = strchr(line, ' ');
  1554. int err;
  1555. if (!end)
  1556. continue;
  1557. *end = '\0';
  1558. err = swapoff(line);
  1559. if (err)
  1560. ULOG_ERR("failed to swapoff %s (%d)\n", line, err);
  1561. }
  1562. fclose(fp);
  1563. } else {
  1564. struct stat s;
  1565. int err;
  1566. if (stat(argv[1], &s) || (!S_ISBLK(s.st_mode) && !S_ISREG(s.st_mode))) {
  1567. ULOG_ERR("%s is not a block device or file\n", argv[1]);
  1568. return -1;
  1569. }
  1570. err = swapoff(argv[1]);
  1571. if (err) {
  1572. ULOG_ERR("failed to swapoff %s (%d)\n", argv[1], err);
  1573. return err;
  1574. }
  1575. }
  1576. return 0;
  1577. }
  1578. int main(int argc, char **argv)
  1579. {
  1580. char *base = basename(*argv);
  1581. umask(0);
  1582. ulog_open(-1, -1, "block");
  1583. ulog_threshold(LOG_NOTICE);
  1584. if (!strcmp(base, "swapon"))
  1585. return main_swapon(argc, argv);
  1586. if (!strcmp(base, "swapoff"))
  1587. return main_swapoff(argc, argv);
  1588. if ((argc > 1) && !strcmp(base, "block")) {
  1589. if (!strcmp(argv[1], "info"))
  1590. return main_info(argc, argv);
  1591. if (!strcmp(argv[1], "detect"))
  1592. return main_detect(argc, argv);
  1593. if (!strcmp(argv[1], "hotplug"))
  1594. return main_hotplug(argc, argv);
  1595. if (!strcmp(argv[1], "autofs"))
  1596. return main_autofs(argc, argv);
  1597. if (!strcmp(argv[1], "extroot"))
  1598. return main_extroot(argc, argv);
  1599. if (!strcmp(argv[1], "mount"))
  1600. return main_mount(argc, argv);
  1601. if (!strcmp(argv[1], "umount"))
  1602. return main_umount(argc, argv);
  1603. if (!strcmp(argv[1], "remount")) {
  1604. int ret = main_umount(argc, argv);
  1605. if (!ret)
  1606. ret = main_mount(argc, argv);
  1607. return ret;
  1608. }
  1609. }
  1610. ULOG_ERR("Usage: block <info|mount|umount|detect>\n");
  1611. return -1;
  1612. }