block.c 34 KB

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