mount.c 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini mount implementation for busybox
  4. *
  5. * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
  6. * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  7. * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
  8. *
  9. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  10. */
  11. // Design notes: There is no spec for mount. Remind me to write one.
  12. //
  13. // mount_main() calls singlemount() which calls mount_it_now().
  14. //
  15. // mount_main() can loop through /etc/fstab for mount -a
  16. // singlemount() can loop through /etc/filesystems for fstype detection.
  17. // mount_it_now() does the actual mount.
  18. //
  19. #include <mntent.h>
  20. #include <syslog.h>
  21. #include <sys/mount.h>
  22. // Grab more as needed from util-linux's mount/mount_constants.h
  23. #ifndef MS_DIRSYNC
  24. # define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
  25. #endif
  26. #ifndef MS_UNION
  27. # define MS_UNION (1 << 8)
  28. #endif
  29. #ifndef MS_BIND
  30. # define MS_BIND (1 << 12)
  31. #endif
  32. #ifndef MS_MOVE
  33. # define MS_MOVE (1 << 13)
  34. #endif
  35. #ifndef MS_RECURSIVE
  36. # define MS_RECURSIVE (1 << 14)
  37. #endif
  38. #ifndef MS_SILENT
  39. # define MS_SILENT (1 << 15)
  40. #endif
  41. // The shared subtree stuff, which went in around 2.6.15
  42. #ifndef MS_UNBINDABLE
  43. # define MS_UNBINDABLE (1 << 17)
  44. #endif
  45. #ifndef MS_PRIVATE
  46. # define MS_PRIVATE (1 << 18)
  47. #endif
  48. #ifndef MS_SLAVE
  49. # define MS_SLAVE (1 << 19)
  50. #endif
  51. #ifndef MS_SHARED
  52. # define MS_SHARED (1 << 20)
  53. #endif
  54. #ifndef MS_RELATIME
  55. # define MS_RELATIME (1 << 21)
  56. #endif
  57. #include "libbb.h"
  58. #if ENABLE_FEATURE_MOUNT_LABEL
  59. # include "volume_id.h"
  60. #else
  61. # define resolve_mount_spec(fsname) ((void)0)
  62. #endif
  63. // Needed for nfs support only
  64. #include <sys/utsname.h>
  65. #undef TRUE
  66. #undef FALSE
  67. #if ENABLE_FEATURE_MOUNT_NFS
  68. /* This is just a warning of a common mistake. Possibly this should be a
  69. * uclibc faq entry rather than in busybox... */
  70. # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
  71. # error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
  72. # endif
  73. # include <rpc/rpc.h>
  74. # include <rpc/pmap_prot.h>
  75. # include <rpc/pmap_clnt.h>
  76. #endif
  77. #if defined(__dietlibc__)
  78. // 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
  79. // dietlibc-0.30 does not have implementation of getmntent_r()
  80. static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
  81. char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
  82. {
  83. struct mntent* ment = getmntent(stream);
  84. return memcpy(result, ment, sizeof(*ment));
  85. }
  86. #endif
  87. // Not real flags, but we want to be able to check for this.
  88. enum {
  89. MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP,
  90. MOUNT_NOAUTO = (1 << 29),
  91. MOUNT_SWAP = (1 << 30),
  92. };
  93. #define OPTION_STR "o:t:rwanfvsiO:"
  94. enum {
  95. OPT_o = (1 << 0),
  96. OPT_t = (1 << 1),
  97. OPT_r = (1 << 2),
  98. OPT_w = (1 << 3),
  99. OPT_a = (1 << 4),
  100. OPT_n = (1 << 5),
  101. OPT_f = (1 << 6),
  102. OPT_v = (1 << 7),
  103. OPT_s = (1 << 8),
  104. OPT_i = (1 << 9),
  105. OPT_O = (1 << 10),
  106. };
  107. #if ENABLE_FEATURE_MTAB_SUPPORT
  108. #define USE_MTAB (!(option_mask32 & OPT_n))
  109. #else
  110. #define USE_MTAB 0
  111. #endif
  112. #if ENABLE_FEATURE_MOUNT_FAKE
  113. #define FAKE_IT (option_mask32 & OPT_f)
  114. #else
  115. #define FAKE_IT 0
  116. #endif
  117. #if ENABLE_FEATURE_MOUNT_HELPERS
  118. #define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
  119. #else
  120. #define HELPERS_ALLOWED 0
  121. #endif
  122. // TODO: more "user" flag compatibility.
  123. // "user" option (from mount manpage):
  124. // Only the user that mounted a filesystem can unmount it again.
  125. // If any user should be able to unmount, then use users instead of user
  126. // in the fstab line. The owner option is similar to the user option,
  127. // with the restriction that the user must be the owner of the special file.
  128. // This may be useful e.g. for /dev/fd if a login script makes
  129. // the console user owner of this device.
  130. // Standard mount options (from -o options or --options),
  131. // with corresponding flags
  132. static const int32_t mount_options[] = {
  133. // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
  134. IF_FEATURE_MOUNT_LOOP(
  135. /* "loop" */ 0,
  136. )
  137. IF_FEATURE_MOUNT_FSTAB(
  138. /* "defaults" */ 0,
  139. /* "quiet" 0 - do not filter out, vfat wants to see it */
  140. /* "noauto" */ MOUNT_NOAUTO,
  141. /* "sw" */ MOUNT_SWAP,
  142. /* "swap" */ MOUNT_SWAP,
  143. IF_DESKTOP(/* "user" */ MOUNT_USERS,)
  144. IF_DESKTOP(/* "users" */ MOUNT_USERS,)
  145. /* "_netdev" */ 0,
  146. )
  147. IF_FEATURE_MOUNT_FLAGS(
  148. // vfs flags
  149. /* "nosuid" */ MS_NOSUID,
  150. /* "suid" */ ~MS_NOSUID,
  151. /* "dev" */ ~MS_NODEV,
  152. /* "nodev" */ MS_NODEV,
  153. /* "exec" */ ~MS_NOEXEC,
  154. /* "noexec" */ MS_NOEXEC,
  155. /* "sync" */ MS_SYNCHRONOUS,
  156. /* "dirsync" */ MS_DIRSYNC,
  157. /* "async" */ ~MS_SYNCHRONOUS,
  158. /* "atime" */ ~MS_NOATIME,
  159. /* "noatime" */ MS_NOATIME,
  160. /* "diratime" */ ~MS_NODIRATIME,
  161. /* "nodiratime" */ MS_NODIRATIME,
  162. /* "mand" */ MS_MANDLOCK,
  163. /* "nomand" */ ~MS_MANDLOCK,
  164. /* "relatime" */ MS_RELATIME,
  165. /* "norelatime" */ ~MS_RELATIME,
  166. /* "loud" */ ~MS_SILENT,
  167. // action flags
  168. /* "union" */ MS_UNION,
  169. /* "bind" */ MS_BIND,
  170. /* "move" */ MS_MOVE,
  171. /* "shared" */ MS_SHARED,
  172. /* "slave" */ MS_SLAVE,
  173. /* "private" */ MS_PRIVATE,
  174. /* "unbindable" */ MS_UNBINDABLE,
  175. /* "rshared" */ MS_SHARED|MS_RECURSIVE,
  176. /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
  177. /* "rprivate" */ MS_SLAVE|MS_RECURSIVE,
  178. /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
  179. )
  180. // Always understood.
  181. /* "ro" */ MS_RDONLY, // vfs flag
  182. /* "rw" */ ~MS_RDONLY, // vfs flag
  183. /* "remount" */ MS_REMOUNT // action flag
  184. };
  185. static const char mount_option_str[] =
  186. IF_FEATURE_MOUNT_LOOP(
  187. "loop\0"
  188. )
  189. IF_FEATURE_MOUNT_FSTAB(
  190. "defaults\0"
  191. // "quiet\0" - do not filter out, vfat wants to see it
  192. "noauto\0"
  193. "sw\0"
  194. "swap\0"
  195. IF_DESKTOP("user\0")
  196. IF_DESKTOP("users\0")
  197. "_netdev\0"
  198. )
  199. IF_FEATURE_MOUNT_FLAGS(
  200. // vfs flags
  201. "nosuid\0"
  202. "suid\0"
  203. "dev\0"
  204. "nodev\0"
  205. "exec\0"
  206. "noexec\0"
  207. "sync\0"
  208. "dirsync\0"
  209. "async\0"
  210. "atime\0"
  211. "noatime\0"
  212. "diratime\0"
  213. "nodiratime\0"
  214. "mand\0"
  215. "nomand\0"
  216. "relatime\0"
  217. "norelatime\0"
  218. "loud\0"
  219. // action flags
  220. "union\0"
  221. "bind\0"
  222. "move\0"
  223. "shared\0"
  224. "slave\0"
  225. "private\0"
  226. "unbindable\0"
  227. "rshared\0"
  228. "rslave\0"
  229. "rprivate\0"
  230. "runbindable\0"
  231. )
  232. // Always understood.
  233. "ro\0" // vfs flag
  234. "rw\0" // vfs flag
  235. "remount\0" // action flag
  236. ;
  237. struct globals {
  238. #if ENABLE_FEATURE_MOUNT_NFS
  239. smalluint nfs_mount_version;
  240. #endif
  241. #if ENABLE_FEATURE_MOUNT_VERBOSE
  242. unsigned verbose;
  243. #endif
  244. llist_t *fslist;
  245. char getmntent_buf[1];
  246. };
  247. enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
  248. #define G (*(struct globals*)&bb_common_bufsiz1)
  249. #define nfs_mount_version (G.nfs_mount_version)
  250. #if ENABLE_FEATURE_MOUNT_VERBOSE
  251. #define verbose (G.verbose )
  252. #else
  253. #define verbose 0
  254. #endif
  255. #define fslist (G.fslist )
  256. #define getmntent_buf (G.getmntent_buf )
  257. #if ENABLE_FEATURE_MOUNT_VERBOSE
  258. static int verbose_mount(const char *source, const char *target,
  259. const char *filesystemtype,
  260. unsigned long mountflags, const void *data)
  261. {
  262. int rc;
  263. errno = 0;
  264. rc = mount(source, target, filesystemtype, mountflags, data);
  265. if (verbose >= 2)
  266. bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
  267. source, target, filesystemtype,
  268. mountflags, (char*)data, rc);
  269. return rc;
  270. }
  271. #else
  272. #define verbose_mount(...) mount(__VA_ARGS__)
  273. #endif
  274. // Append mount options to string
  275. static void append_mount_options(char **oldopts, const char *newopts)
  276. {
  277. if (*oldopts && **oldopts) {
  278. // Do not insert options which are already there
  279. while (newopts[0]) {
  280. char *p;
  281. int len = strlen(newopts);
  282. p = strchr(newopts, ',');
  283. if (p) len = p - newopts;
  284. p = *oldopts;
  285. while (1) {
  286. if (!strncmp(p, newopts, len)
  287. && (p[len] == ',' || p[len] == '\0'))
  288. goto skip;
  289. p = strchr(p,',');
  290. if (!p) break;
  291. p++;
  292. }
  293. p = xasprintf("%s,%.*s", *oldopts, len, newopts);
  294. free(*oldopts);
  295. *oldopts = p;
  296. skip:
  297. newopts += len;
  298. while (newopts[0] == ',') newopts++;
  299. }
  300. } else {
  301. if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
  302. *oldopts = xstrdup(newopts);
  303. }
  304. }
  305. // Use the mount_options list to parse options into flags.
  306. // Also return list of unrecognized options if unrecognized != NULL
  307. static long parse_mount_options(char *options, char **unrecognized)
  308. {
  309. long flags = MS_SILENT;
  310. // Loop through options
  311. for (;;) {
  312. unsigned i;
  313. char *comma = strchr(options, ',');
  314. const char *option_str = mount_option_str;
  315. if (comma) *comma = '\0';
  316. // FIXME: use hasmntopt()
  317. // Find this option in mount_options
  318. for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
  319. if (!strcasecmp(option_str, options)) {
  320. long fl = mount_options[i];
  321. if (fl < 0) flags &= fl;
  322. else flags |= fl;
  323. break;
  324. }
  325. option_str += strlen(option_str) + 1;
  326. }
  327. // If unrecognized not NULL, append unrecognized mount options
  328. if (unrecognized && i == ARRAY_SIZE(mount_options)) {
  329. // Add it to strflags, to pass on to kernel
  330. i = *unrecognized ? strlen(*unrecognized) : 0;
  331. *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2);
  332. // Comma separated if it's not the first one
  333. if (i) (*unrecognized)[i++] = ',';
  334. strcpy((*unrecognized)+i, options);
  335. }
  336. if (!comma)
  337. break;
  338. // Advance to next option
  339. *comma = ',';
  340. options = ++comma;
  341. }
  342. return flags;
  343. }
  344. // Return a list of all block device backed filesystems
  345. static llist_t *get_block_backed_filesystems(void)
  346. {
  347. static const char filesystems[2][sizeof("/proc/filesystems")] = {
  348. "/etc/filesystems",
  349. "/proc/filesystems",
  350. };
  351. char *fs, *buf;
  352. llist_t *list = NULL;
  353. int i;
  354. FILE *f;
  355. for (i = 0; i < 2; i++) {
  356. f = fopen_for_read(filesystems[i]);
  357. if (!f) continue;
  358. while ((buf = xmalloc_fgetline(f)) != NULL) {
  359. if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
  360. continue;
  361. fs = skip_whitespace(buf);
  362. if (*fs == '#' || *fs == '*' || !*fs)
  363. continue;
  364. llist_add_to_end(&list, xstrdup(fs));
  365. free(buf);
  366. }
  367. if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
  368. }
  369. return list;
  370. }
  371. #if ENABLE_FEATURE_CLEAN_UP
  372. static void delete_block_backed_filesystems(void)
  373. {
  374. llist_free(fslist, free);
  375. }
  376. #else
  377. void delete_block_backed_filesystems(void);
  378. #endif
  379. // Perform actual mount of specific filesystem at specific location.
  380. // NB: mp->xxx fields may be trashed on exit
  381. static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
  382. {
  383. int rc = 0;
  384. if (FAKE_IT) {
  385. if (verbose >= 2)
  386. bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
  387. mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
  388. vfsflags, filteropts);
  389. goto mtab;
  390. }
  391. // Mount, with fallback to read-only if necessary.
  392. for (;;) {
  393. errno = 0;
  394. rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
  395. vfsflags, filteropts);
  396. // If mount failed, try
  397. // helper program mount.<mnt_type>
  398. if (HELPERS_ALLOWED && rc && mp->mnt_type) {
  399. char *args[8];
  400. int errno_save = errno;
  401. args[0] = xasprintf("mount.%s", mp->mnt_type);
  402. rc = 1;
  403. if (FAKE_IT)
  404. args[rc++] = (char *)"-f";
  405. if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
  406. args[rc++] = (char *)"-n";
  407. args[rc++] = mp->mnt_fsname;
  408. args[rc++] = mp->mnt_dir;
  409. if (filteropts) {
  410. args[rc++] = (char *)"-o";
  411. args[rc++] = filteropts;
  412. }
  413. args[rc] = NULL;
  414. rc = wait4pid(spawn(args));
  415. free(args[0]);
  416. if (!rc)
  417. break;
  418. errno = errno_save;
  419. }
  420. if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
  421. break;
  422. if (!(vfsflags & MS_SILENT))
  423. bb_error_msg("%s is write-protected, mounting read-only",
  424. mp->mnt_fsname);
  425. vfsflags |= MS_RDONLY;
  426. }
  427. // Abort entirely if permission denied.
  428. if (rc && errno == EPERM)
  429. bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
  430. // If the mount was successful, and we're maintaining an old-style
  431. // mtab file by hand, add the new entry to it now.
  432. mtab:
  433. if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
  434. char *fsname;
  435. FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
  436. const char *option_str = mount_option_str;
  437. int i;
  438. if (!mountTable) {
  439. bb_error_msg("no %s", bb_path_mtab_file);
  440. goto ret;
  441. }
  442. // Add vfs string flags
  443. for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
  444. if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
  445. append_mount_options(&(mp->mnt_opts), option_str);
  446. option_str += strlen(option_str) + 1;
  447. }
  448. // Remove trailing / (if any) from directory we mounted on
  449. i = strlen(mp->mnt_dir) - 1;
  450. if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
  451. // Convert to canonical pathnames as needed
  452. mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
  453. fsname = 0;
  454. if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
  455. mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
  456. mp->mnt_type = (char*)"bind";
  457. }
  458. mp->mnt_freq = mp->mnt_passno = 0;
  459. // Write and close.
  460. addmntent(mountTable, mp);
  461. endmntent(mountTable);
  462. if (ENABLE_FEATURE_CLEAN_UP) {
  463. free(mp->mnt_dir);
  464. free(fsname);
  465. }
  466. }
  467. ret:
  468. return rc;
  469. }
  470. #if ENABLE_FEATURE_MOUNT_NFS
  471. /*
  472. * Linux NFS mount
  473. * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  474. *
  475. * Licensed under GPLv2, see file LICENSE in this tarball for details.
  476. *
  477. * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
  478. * numbers to be specified on the command line.
  479. *
  480. * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
  481. * Omit the call to connect() for Linux version 1.3.11 or later.
  482. *
  483. * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
  484. * Implemented the "bg", "fg" and "retry" mount options for NFS.
  485. *
  486. * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
  487. * - added Native Language Support
  488. *
  489. * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
  490. * plus NFSv3 stuff.
  491. */
  492. #define MOUNTPORT 635
  493. #define MNTPATHLEN 1024
  494. #define MNTNAMLEN 255
  495. #define FHSIZE 32
  496. #define FHSIZE3 64
  497. typedef char fhandle[FHSIZE];
  498. typedef struct {
  499. unsigned int fhandle3_len;
  500. char *fhandle3_val;
  501. } fhandle3;
  502. enum mountstat3 {
  503. MNT_OK = 0,
  504. MNT3ERR_PERM = 1,
  505. MNT3ERR_NOENT = 2,
  506. MNT3ERR_IO = 5,
  507. MNT3ERR_ACCES = 13,
  508. MNT3ERR_NOTDIR = 20,
  509. MNT3ERR_INVAL = 22,
  510. MNT3ERR_NAMETOOLONG = 63,
  511. MNT3ERR_NOTSUPP = 10004,
  512. MNT3ERR_SERVERFAULT = 10006,
  513. };
  514. typedef enum mountstat3 mountstat3;
  515. struct fhstatus {
  516. unsigned int fhs_status;
  517. union {
  518. fhandle fhs_fhandle;
  519. } fhstatus_u;
  520. };
  521. typedef struct fhstatus fhstatus;
  522. struct mountres3_ok {
  523. fhandle3 fhandle;
  524. struct {
  525. unsigned int auth_flavours_len;
  526. char *auth_flavours_val;
  527. } auth_flavours;
  528. };
  529. typedef struct mountres3_ok mountres3_ok;
  530. struct mountres3 {
  531. mountstat3 fhs_status;
  532. union {
  533. mountres3_ok mountinfo;
  534. } mountres3_u;
  535. };
  536. typedef struct mountres3 mountres3;
  537. typedef char *dirpath;
  538. typedef char *name;
  539. typedef struct mountbody *mountlist;
  540. struct mountbody {
  541. name ml_hostname;
  542. dirpath ml_directory;
  543. mountlist ml_next;
  544. };
  545. typedef struct mountbody mountbody;
  546. typedef struct groupnode *groups;
  547. struct groupnode {
  548. name gr_name;
  549. groups gr_next;
  550. };
  551. typedef struct groupnode groupnode;
  552. typedef struct exportnode *exports;
  553. struct exportnode {
  554. dirpath ex_dir;
  555. groups ex_groups;
  556. exports ex_next;
  557. };
  558. typedef struct exportnode exportnode;
  559. struct ppathcnf {
  560. int pc_link_max;
  561. short pc_max_canon;
  562. short pc_max_input;
  563. short pc_name_max;
  564. short pc_path_max;
  565. short pc_pipe_buf;
  566. uint8_t pc_vdisable;
  567. char pc_xxx;
  568. short pc_mask[2];
  569. };
  570. typedef struct ppathcnf ppathcnf;
  571. #define MOUNTPROG 100005
  572. #define MOUNTVERS 1
  573. #define MOUNTPROC_NULL 0
  574. #define MOUNTPROC_MNT 1
  575. #define MOUNTPROC_DUMP 2
  576. #define MOUNTPROC_UMNT 3
  577. #define MOUNTPROC_UMNTALL 4
  578. #define MOUNTPROC_EXPORT 5
  579. #define MOUNTPROC_EXPORTALL 6
  580. #define MOUNTVERS_POSIX 2
  581. #define MOUNTPROC_PATHCONF 7
  582. #define MOUNT_V3 3
  583. #define MOUNTPROC3_NULL 0
  584. #define MOUNTPROC3_MNT 1
  585. #define MOUNTPROC3_DUMP 2
  586. #define MOUNTPROC3_UMNT 3
  587. #define MOUNTPROC3_UMNTALL 4
  588. #define MOUNTPROC3_EXPORT 5
  589. enum {
  590. #ifndef NFS_FHSIZE
  591. NFS_FHSIZE = 32,
  592. #endif
  593. #ifndef NFS_PORT
  594. NFS_PORT = 2049
  595. #endif
  596. };
  597. /*
  598. * We want to be able to compile mount on old kernels in such a way
  599. * that the binary will work well on more recent kernels.
  600. * Thus, if necessary we teach nfsmount.c the structure of new fields
  601. * that will come later.
  602. *
  603. * Moreover, the new kernel includes conflict with glibc includes
  604. * so it is easiest to ignore the kernel altogether (at compile time).
  605. */
  606. struct nfs2_fh {
  607. char data[32];
  608. };
  609. struct nfs3_fh {
  610. unsigned short size;
  611. unsigned char data[64];
  612. };
  613. struct nfs_mount_data {
  614. int version; /* 1 */
  615. int fd; /* 1 */
  616. struct nfs2_fh old_root; /* 1 */
  617. int flags; /* 1 */
  618. int rsize; /* 1 */
  619. int wsize; /* 1 */
  620. int timeo; /* 1 */
  621. int retrans; /* 1 */
  622. int acregmin; /* 1 */
  623. int acregmax; /* 1 */
  624. int acdirmin; /* 1 */
  625. int acdirmax; /* 1 */
  626. struct sockaddr_in addr; /* 1 */
  627. char hostname[256]; /* 1 */
  628. int namlen; /* 2 */
  629. unsigned int bsize; /* 3 */
  630. struct nfs3_fh root; /* 4 */
  631. };
  632. /* bits in the flags field */
  633. enum {
  634. NFS_MOUNT_SOFT = 0x0001, /* 1 */
  635. NFS_MOUNT_INTR = 0x0002, /* 1 */
  636. NFS_MOUNT_SECURE = 0x0004, /* 1 */
  637. NFS_MOUNT_POSIX = 0x0008, /* 1 */
  638. NFS_MOUNT_NOCTO = 0x0010, /* 1 */
  639. NFS_MOUNT_NOAC = 0x0020, /* 1 */
  640. NFS_MOUNT_TCP = 0x0040, /* 2 */
  641. NFS_MOUNT_VER3 = 0x0080, /* 3 */
  642. NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
  643. NFS_MOUNT_NONLM = 0x0200, /* 3 */
  644. NFS_MOUNT_NORDIRPLUS = 0x4000
  645. };
  646. /*
  647. * We need to translate between nfs status return values and
  648. * the local errno values which may not be the same.
  649. *
  650. * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
  651. * "after #include <errno.h> the symbol errno is reserved for any use,
  652. * it cannot even be used as a struct tag or field name".
  653. */
  654. #ifndef EDQUOT
  655. # define EDQUOT ENOSPC
  656. #endif
  657. /* Convert each NFSERR_BLAH into EBLAH */
  658. static const uint8_t nfs_err_stat[] = {
  659. 1, 2, 5, 6, 13, 17,
  660. 19, 20, 21, 22, 27, 28,
  661. 30, 63, 66, 69, 70, 71
  662. };
  663. static const uint8_t nfs_err_errnum[] = {
  664. EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
  665. ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
  666. EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
  667. };
  668. static char *nfs_strerror(int status)
  669. {
  670. int i;
  671. for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
  672. if (nfs_err_stat[i] == status)
  673. return strerror(nfs_err_errnum[i]);
  674. }
  675. return xasprintf("unknown nfs status return value: %d", status);
  676. }
  677. static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
  678. {
  679. if (!xdr_opaque(xdrs, objp, FHSIZE))
  680. return FALSE;
  681. return TRUE;
  682. }
  683. static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
  684. {
  685. if (!xdr_u_int(xdrs, &objp->fhs_status))
  686. return FALSE;
  687. switch (objp->fhs_status) {
  688. case 0:
  689. if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
  690. return FALSE;
  691. break;
  692. default:
  693. break;
  694. }
  695. return TRUE;
  696. }
  697. static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
  698. {
  699. if (!xdr_string(xdrs, objp, MNTPATHLEN))
  700. return FALSE;
  701. return TRUE;
  702. }
  703. static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
  704. {
  705. if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
  706. (unsigned int *) &objp->fhandle3_len,
  707. FHSIZE3)
  708. ) {
  709. return FALSE;
  710. }
  711. return TRUE;
  712. }
  713. static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
  714. {
  715. if (!xdr_fhandle3(xdrs, &objp->fhandle))
  716. return FALSE;
  717. if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
  718. &(objp->auth_flavours.auth_flavours_len),
  719. ~0,
  720. sizeof(int),
  721. (xdrproc_t) xdr_int)
  722. ) {
  723. return FALSE;
  724. }
  725. return TRUE;
  726. }
  727. static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
  728. {
  729. if (!xdr_enum(xdrs, (enum_t *) objp))
  730. return FALSE;
  731. return TRUE;
  732. }
  733. static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
  734. {
  735. if (!xdr_mountstat3(xdrs, &objp->fhs_status))
  736. return FALSE;
  737. switch (objp->fhs_status) {
  738. case MNT_OK:
  739. if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
  740. return FALSE;
  741. break;
  742. default:
  743. break;
  744. }
  745. return TRUE;
  746. }
  747. #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
  748. /*
  749. * Unfortunately, the kernel prints annoying console messages
  750. * in case of an unexpected nfs mount version (instead of
  751. * just returning some error). Therefore we'll have to try
  752. * and figure out what version the kernel expects.
  753. *
  754. * Variables:
  755. * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
  756. * NFS_MOUNT_VERSION: these nfsmount sources at compile time
  757. * nfs_mount_version: version this source and running kernel can handle
  758. */
  759. static void
  760. find_kernel_nfs_mount_version(void)
  761. {
  762. int kernel_version;
  763. if (nfs_mount_version)
  764. return;
  765. nfs_mount_version = 4; /* default */
  766. kernel_version = get_linux_version_code();
  767. if (kernel_version) {
  768. if (kernel_version < KERNEL_VERSION(2,2,18))
  769. nfs_mount_version = 3;
  770. /* else v4 since 2.3.99pre4 */
  771. }
  772. }
  773. static void
  774. get_mountport(struct pmap *pm_mnt,
  775. struct sockaddr_in *server_addr,
  776. long unsigned prog,
  777. long unsigned version,
  778. long unsigned proto,
  779. long unsigned port)
  780. {
  781. struct pmaplist *pmap;
  782. server_addr->sin_port = PMAPPORT;
  783. /* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
  784. * I understand it like "IPv6 for this is not 100% ready" */
  785. pmap = pmap_getmaps(server_addr);
  786. if (version > MAX_NFSPROT)
  787. version = MAX_NFSPROT;
  788. if (!prog)
  789. prog = MOUNTPROG;
  790. pm_mnt->pm_prog = prog;
  791. pm_mnt->pm_vers = version;
  792. pm_mnt->pm_prot = proto;
  793. pm_mnt->pm_port = port;
  794. while (pmap) {
  795. if (pmap->pml_map.pm_prog != prog)
  796. goto next;
  797. if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
  798. goto next;
  799. if (version > 2 && pmap->pml_map.pm_vers != version)
  800. goto next;
  801. if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
  802. goto next;
  803. if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
  804. (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto) ||
  805. (port && pmap->pml_map.pm_port != port))
  806. goto next;
  807. memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
  808. next:
  809. pmap = pmap->pml_next;
  810. }
  811. if (!pm_mnt->pm_vers)
  812. pm_mnt->pm_vers = MOUNTVERS;
  813. if (!pm_mnt->pm_port)
  814. pm_mnt->pm_port = MOUNTPORT;
  815. if (!pm_mnt->pm_prot)
  816. pm_mnt->pm_prot = IPPROTO_TCP;
  817. }
  818. #if BB_MMU
  819. static int daemonize(void)
  820. {
  821. int pid = fork();
  822. if (pid < 0) /* error */
  823. return -errno;
  824. if (pid > 0) /* parent */
  825. return 0;
  826. /* child */
  827. close(0);
  828. xopen(bb_dev_null, O_RDWR);
  829. xdup2(0, 1);
  830. xdup2(0, 2);
  831. setsid();
  832. openlog(applet_name, LOG_PID, LOG_DAEMON);
  833. logmode = LOGMODE_SYSLOG;
  834. return 1;
  835. }
  836. #else
  837. static inline int daemonize(void) { return -ENOSYS; }
  838. #endif
  839. /* TODO */
  840. static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
  841. {
  842. return 0;
  843. }
  844. /* RPC strerror analogs are terminally idiotic:
  845. * *mandatory* prefix and \n at end.
  846. * This hopefully helps. Usage:
  847. * error_msg_rpc(clnt_*error*(" ")) */
  848. static void error_msg_rpc(const char *msg)
  849. {
  850. int len;
  851. while (msg[0] == ' ' || msg[0] == ':') msg++;
  852. len = strlen(msg);
  853. while (len && msg[len-1] == '\n') len--;
  854. bb_error_msg("%.*s", len, msg);
  855. }
  856. /* NB: mp->xxx fields may be trashed on exit */
  857. static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
  858. {
  859. CLIENT *mclient;
  860. char *hostname;
  861. char *pathname;
  862. char *mounthost;
  863. /* prior to 2.6.23, kernel took NFS options in a form of this struct
  864. * only. 2.6.23+ looks at data->version, and if it's not 1..6,
  865. * then data pointer is interpreted as a string. */
  866. struct nfs_mount_data data;
  867. char *opt;
  868. struct hostent *hp;
  869. struct sockaddr_in server_addr;
  870. struct sockaddr_in mount_server_addr;
  871. int msock, fsock;
  872. union {
  873. struct fhstatus nfsv2;
  874. struct mountres3 nfsv3;
  875. } status;
  876. int daemonized;
  877. char *s;
  878. int port;
  879. int mountport;
  880. int proto;
  881. #if BB_MMU
  882. smallint bg = 0;
  883. #else
  884. enum { bg = 0 };
  885. #endif
  886. int retry;
  887. int mountprog;
  888. int mountvers;
  889. int nfsprog;
  890. int nfsvers;
  891. int retval;
  892. /* these all are one-bit really. gcc 4.3.1 likes this combination: */
  893. smallint tcp;
  894. smallint soft;
  895. int intr;
  896. int posix;
  897. int nocto;
  898. int noac;
  899. int nordirplus;
  900. int nolock;
  901. find_kernel_nfs_mount_version();
  902. daemonized = 0;
  903. mounthost = NULL;
  904. retval = ETIMEDOUT;
  905. msock = fsock = -1;
  906. mclient = NULL;
  907. /* NB: hostname, mounthost, filteropts must be free()d prior to return */
  908. filteropts = xstrdup(filteropts); /* going to trash it later... */
  909. hostname = xstrdup(mp->mnt_fsname);
  910. /* mount_main() guarantees that ':' is there */
  911. s = strchr(hostname, ':');
  912. pathname = s + 1;
  913. *s = '\0';
  914. /* Ignore all but first hostname in replicated mounts
  915. until they can be fully supported. (mack@sgi.com) */
  916. s = strchr(hostname, ',');
  917. if (s) {
  918. *s = '\0';
  919. bb_error_msg("warning: multiple hostnames not supported");
  920. }
  921. server_addr.sin_family = AF_INET;
  922. if (!inet_aton(hostname, &server_addr.sin_addr)) {
  923. hp = gethostbyname(hostname);
  924. if (hp == NULL) {
  925. bb_herror_msg("%s", hostname);
  926. goto fail;
  927. }
  928. if ((size_t)hp->h_length > sizeof(struct in_addr)) {
  929. bb_error_msg("got bad hp->h_length");
  930. hp->h_length = sizeof(struct in_addr);
  931. }
  932. memcpy(&server_addr.sin_addr,
  933. hp->h_addr, hp->h_length);
  934. }
  935. memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
  936. /* add IP address to mtab options for use when unmounting */
  937. if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
  938. mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
  939. } else {
  940. char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
  941. mp->mnt_opts[0] ? "," : "",
  942. inet_ntoa(server_addr.sin_addr));
  943. free(mp->mnt_opts);
  944. mp->mnt_opts = tmp;
  945. }
  946. /* Set default options.
  947. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
  948. * let the kernel decide.
  949. * timeo is filled in after we know whether it'll be TCP or UDP. */
  950. memset(&data, 0, sizeof(data));
  951. data.retrans = 3;
  952. data.acregmin = 3;
  953. data.acregmax = 60;
  954. data.acdirmin = 30;
  955. data.acdirmax = 60;
  956. data.namlen = NAME_MAX;
  957. soft = 0;
  958. intr = 0;
  959. posix = 0;
  960. nocto = 0;
  961. nolock = 0;
  962. noac = 0;
  963. nordirplus = 0;
  964. retry = 10000; /* 10000 minutes ~ 1 week */
  965. tcp = 0;
  966. mountprog = MOUNTPROG;
  967. mountvers = 0;
  968. port = 0;
  969. mountport = 0;
  970. nfsprog = 100003;
  971. nfsvers = 0;
  972. /* parse options */
  973. if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
  974. char *opteq = strchr(opt, '=');
  975. if (opteq) {
  976. int val, idx;
  977. static const char options[] ALIGN1 =
  978. /* 0 */ "rsize\0"
  979. /* 1 */ "wsize\0"
  980. /* 2 */ "timeo\0"
  981. /* 3 */ "retrans\0"
  982. /* 4 */ "acregmin\0"
  983. /* 5 */ "acregmax\0"
  984. /* 6 */ "acdirmin\0"
  985. /* 7 */ "acdirmax\0"
  986. /* 8 */ "actimeo\0"
  987. /* 9 */ "retry\0"
  988. /* 10 */ "port\0"
  989. /* 11 */ "mountport\0"
  990. /* 12 */ "mounthost\0"
  991. /* 13 */ "mountprog\0"
  992. /* 14 */ "mountvers\0"
  993. /* 15 */ "nfsprog\0"
  994. /* 16 */ "nfsvers\0"
  995. /* 17 */ "vers\0"
  996. /* 18 */ "proto\0"
  997. /* 19 */ "namlen\0"
  998. /* 20 */ "addr\0";
  999. *opteq++ = '\0';
  1000. idx = index_in_strings(options, opt);
  1001. switch (idx) {
  1002. case 12: // "mounthost"
  1003. mounthost = xstrndup(opteq,
  1004. strcspn(opteq, " \t\n\r,"));
  1005. continue;
  1006. case 18: // "proto"
  1007. if (!strncmp(opteq, "tcp", 3))
  1008. tcp = 1;
  1009. else if (!strncmp(opteq, "udp", 3))
  1010. tcp = 0;
  1011. else
  1012. bb_error_msg("warning: unrecognized proto= option");
  1013. continue;
  1014. case 20: // "addr" - ignore
  1015. continue;
  1016. }
  1017. val = xatoi_u(opteq);
  1018. switch (idx) {
  1019. case 0: // "rsize"
  1020. data.rsize = val;
  1021. continue;
  1022. case 1: // "wsize"
  1023. data.wsize = val;
  1024. continue;
  1025. case 2: // "timeo"
  1026. data.timeo = val;
  1027. continue;
  1028. case 3: // "retrans"
  1029. data.retrans = val;
  1030. continue;
  1031. case 4: // "acregmin"
  1032. data.acregmin = val;
  1033. continue;
  1034. case 5: // "acregmax"
  1035. data.acregmax = val;
  1036. continue;
  1037. case 6: // "acdirmin"
  1038. data.acdirmin = val;
  1039. continue;
  1040. case 7: // "acdirmax"
  1041. data.acdirmax = val;
  1042. continue;
  1043. case 8: // "actimeo"
  1044. data.acregmin = val;
  1045. data.acregmax = val;
  1046. data.acdirmin = val;
  1047. data.acdirmax = val;
  1048. continue;
  1049. case 9: // "retry"
  1050. retry = val;
  1051. continue;
  1052. case 10: // "port"
  1053. port = val;
  1054. continue;
  1055. case 11: // "mountport"
  1056. mountport = val;
  1057. continue;
  1058. case 13: // "mountprog"
  1059. mountprog = val;
  1060. continue;
  1061. case 14: // "mountvers"
  1062. mountvers = val;
  1063. continue;
  1064. case 15: // "nfsprog"
  1065. nfsprog = val;
  1066. continue;
  1067. case 16: // "nfsvers"
  1068. case 17: // "vers"
  1069. nfsvers = val;
  1070. continue;
  1071. case 19: // "namlen"
  1072. //if (nfs_mount_version >= 2)
  1073. data.namlen = val;
  1074. //else
  1075. // bb_error_msg("warning: option namlen is not supported\n");
  1076. continue;
  1077. default:
  1078. bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
  1079. goto fail;
  1080. }
  1081. }
  1082. else { /* not of the form opt=val */
  1083. static const char options[] ALIGN1 =
  1084. "bg\0"
  1085. "fg\0"
  1086. "soft\0"
  1087. "hard\0"
  1088. "intr\0"
  1089. "posix\0"
  1090. "cto\0"
  1091. "ac\0"
  1092. "tcp\0"
  1093. "udp\0"
  1094. "lock\0"
  1095. "rdirplus\0";
  1096. int val = 1;
  1097. if (!strncmp(opt, "no", 2)) {
  1098. val = 0;
  1099. opt += 2;
  1100. }
  1101. switch (index_in_strings(options, opt)) {
  1102. case 0: // "bg"
  1103. #if BB_MMU
  1104. bg = val;
  1105. #endif
  1106. break;
  1107. case 1: // "fg"
  1108. #if BB_MMU
  1109. bg = !val;
  1110. #endif
  1111. break;
  1112. case 2: // "soft"
  1113. soft = val;
  1114. break;
  1115. case 3: // "hard"
  1116. soft = !val;
  1117. break;
  1118. case 4: // "intr"
  1119. intr = val;
  1120. break;
  1121. case 5: // "posix"
  1122. posix = val;
  1123. break;
  1124. case 6: // "cto"
  1125. nocto = !val;
  1126. break;
  1127. case 7: // "ac"
  1128. noac = !val;
  1129. break;
  1130. case 8: // "tcp"
  1131. tcp = val;
  1132. break;
  1133. case 9: // "udp"
  1134. tcp = !val;
  1135. break;
  1136. case 10: // "lock"
  1137. if (nfs_mount_version >= 3)
  1138. nolock = !val;
  1139. else
  1140. bb_error_msg("warning: option nolock is not supported");
  1141. break;
  1142. case 11: //rdirplus
  1143. nordirplus = !val;
  1144. break;
  1145. default:
  1146. bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
  1147. goto fail;
  1148. }
  1149. }
  1150. }
  1151. proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
  1152. data.flags = (soft ? NFS_MOUNT_SOFT : 0)
  1153. | (intr ? NFS_MOUNT_INTR : 0)
  1154. | (posix ? NFS_MOUNT_POSIX : 0)
  1155. | (nocto ? NFS_MOUNT_NOCTO : 0)
  1156. | (noac ? NFS_MOUNT_NOAC : 0)
  1157. | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
  1158. if (nfs_mount_version >= 2)
  1159. data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
  1160. if (nfs_mount_version >= 3)
  1161. data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
  1162. if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
  1163. bb_error_msg("NFSv%d not supported", nfsvers);
  1164. goto fail;
  1165. }
  1166. if (nfsvers && !mountvers)
  1167. mountvers = (nfsvers < 3) ? 1 : nfsvers;
  1168. if (nfsvers && nfsvers < mountvers) {
  1169. mountvers = nfsvers;
  1170. }
  1171. /* Adjust options if none specified */
  1172. if (!data.timeo)
  1173. data.timeo = tcp ? 70 : 7;
  1174. data.version = nfs_mount_version;
  1175. if (vfsflags & MS_REMOUNT)
  1176. goto do_mount;
  1177. /*
  1178. * If the previous mount operation on the same host was
  1179. * backgrounded, and the "bg" for this mount is also set,
  1180. * give up immediately, to avoid the initial timeout.
  1181. */
  1182. if (bg && we_saw_this_host_before(hostname)) {
  1183. daemonized = daemonize();
  1184. if (daemonized <= 0) { /* parent or error */
  1185. retval = -daemonized;
  1186. goto ret;
  1187. }
  1188. }
  1189. /* Create mount daemon client */
  1190. /* See if the nfs host = mount host. */
  1191. if (mounthost) {
  1192. if (mounthost[0] >= '0' && mounthost[0] <= '9') {
  1193. mount_server_addr.sin_family = AF_INET;
  1194. mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
  1195. } else {
  1196. hp = gethostbyname(mounthost);
  1197. if (hp == NULL) {
  1198. bb_herror_msg("%s", mounthost);
  1199. goto fail;
  1200. }
  1201. if ((size_t)hp->h_length > sizeof(struct in_addr)) {
  1202. bb_error_msg("got bad hp->h_length");
  1203. hp->h_length = sizeof(struct in_addr);
  1204. }
  1205. mount_server_addr.sin_family = AF_INET;
  1206. memcpy(&mount_server_addr.sin_addr,
  1207. hp->h_addr, hp->h_length);
  1208. }
  1209. }
  1210. /*
  1211. * The following loop implements the mount retries. When the mount
  1212. * times out, and the "bg" option is set, we background ourself
  1213. * and continue trying.
  1214. *
  1215. * The case where the mount point is not present and the "bg"
  1216. * option is set, is treated as a timeout. This is done to
  1217. * support nested mounts.
  1218. *
  1219. * The "retry" count specified by the user is the number of
  1220. * minutes to retry before giving up.
  1221. */
  1222. {
  1223. struct timeval total_timeout;
  1224. struct timeval retry_timeout;
  1225. struct pmap pm_mnt;
  1226. time_t t;
  1227. time_t prevt;
  1228. time_t timeout;
  1229. retry_timeout.tv_sec = 3;
  1230. retry_timeout.tv_usec = 0;
  1231. total_timeout.tv_sec = 20;
  1232. total_timeout.tv_usec = 0;
  1233. /* FIXME: use monotonic()? */
  1234. timeout = time(NULL) + 60 * retry;
  1235. prevt = 0;
  1236. t = 30;
  1237. retry:
  1238. /* Be careful not to use too many CPU cycles */
  1239. if (t - prevt < 30)
  1240. sleep(30);
  1241. get_mountport(&pm_mnt, &mount_server_addr,
  1242. mountprog,
  1243. mountvers,
  1244. proto,
  1245. mountport);
  1246. nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
  1247. /* contact the mount daemon via TCP */
  1248. mount_server_addr.sin_port = htons(pm_mnt.pm_port);
  1249. msock = RPC_ANYSOCK;
  1250. switch (pm_mnt.pm_prot) {
  1251. case IPPROTO_UDP:
  1252. mclient = clntudp_create(&mount_server_addr,
  1253. pm_mnt.pm_prog,
  1254. pm_mnt.pm_vers,
  1255. retry_timeout,
  1256. &msock);
  1257. if (mclient)
  1258. break;
  1259. mount_server_addr.sin_port = htons(pm_mnt.pm_port);
  1260. msock = RPC_ANYSOCK;
  1261. case IPPROTO_TCP:
  1262. mclient = clnttcp_create(&mount_server_addr,
  1263. pm_mnt.pm_prog,
  1264. pm_mnt.pm_vers,
  1265. &msock, 0, 0);
  1266. break;
  1267. default:
  1268. mclient = NULL;
  1269. }
  1270. if (!mclient) {
  1271. if (!daemonized && prevt == 0)
  1272. error_msg_rpc(clnt_spcreateerror(" "));
  1273. } else {
  1274. enum clnt_stat clnt_stat;
  1275. /* Try to mount hostname:pathname */
  1276. mclient->cl_auth = authunix_create_default();
  1277. /* Make pointers in xdr_mountres3 NULL so
  1278. * that xdr_array allocates memory for us
  1279. */
  1280. memset(&status, 0, sizeof(status));
  1281. if (pm_mnt.pm_vers == 3)
  1282. clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
  1283. (xdrproc_t) xdr_dirpath,
  1284. (caddr_t) &pathname,
  1285. (xdrproc_t) xdr_mountres3,
  1286. (caddr_t) &status,
  1287. total_timeout);
  1288. else
  1289. clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
  1290. (xdrproc_t) xdr_dirpath,
  1291. (caddr_t) &pathname,
  1292. (xdrproc_t) xdr_fhstatus,
  1293. (caddr_t) &status,
  1294. total_timeout);
  1295. if (clnt_stat == RPC_SUCCESS)
  1296. goto prepare_kernel_data; /* we're done */
  1297. if (errno != ECONNREFUSED) {
  1298. error_msg_rpc(clnt_sperror(mclient, " "));
  1299. goto fail; /* don't retry */
  1300. }
  1301. /* Connection refused */
  1302. if (!daemonized && prevt == 0) /* print just once */
  1303. error_msg_rpc(clnt_sperror(mclient, " "));
  1304. auth_destroy(mclient->cl_auth);
  1305. clnt_destroy(mclient);
  1306. mclient = NULL;
  1307. close(msock);
  1308. msock = -1;
  1309. }
  1310. /* Timeout. We are going to retry... maybe */
  1311. if (!bg)
  1312. goto fail;
  1313. if (!daemonized) {
  1314. daemonized = daemonize();
  1315. if (daemonized <= 0) { /* parent or error */
  1316. retval = -daemonized;
  1317. goto ret;
  1318. }
  1319. }
  1320. prevt = t;
  1321. t = time(NULL);
  1322. if (t >= timeout)
  1323. /* TODO error message */
  1324. goto fail;
  1325. goto retry;
  1326. }
  1327. prepare_kernel_data:
  1328. if (nfsvers == 2) {
  1329. if (status.nfsv2.fhs_status != 0) {
  1330. bb_error_msg("%s:%s failed, reason given by server: %s",
  1331. hostname, pathname,
  1332. nfs_strerror(status.nfsv2.fhs_status));
  1333. goto fail;
  1334. }
  1335. memcpy(data.root.data,
  1336. (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
  1337. NFS_FHSIZE);
  1338. data.root.size = NFS_FHSIZE;
  1339. memcpy(data.old_root.data,
  1340. (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
  1341. NFS_FHSIZE);
  1342. } else {
  1343. fhandle3 *my_fhandle;
  1344. if (status.nfsv3.fhs_status != 0) {
  1345. bb_error_msg("%s:%s failed, reason given by server: %s",
  1346. hostname, pathname,
  1347. nfs_strerror(status.nfsv3.fhs_status));
  1348. goto fail;
  1349. }
  1350. my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
  1351. memset(data.old_root.data, 0, NFS_FHSIZE);
  1352. memset(&data.root, 0, sizeof(data.root));
  1353. data.root.size = my_fhandle->fhandle3_len;
  1354. memcpy(data.root.data,
  1355. (char *) my_fhandle->fhandle3_val,
  1356. my_fhandle->fhandle3_len);
  1357. data.flags |= NFS_MOUNT_VER3;
  1358. }
  1359. /* Create nfs socket for kernel */
  1360. if (tcp) {
  1361. if (nfs_mount_version < 3) {
  1362. bb_error_msg("NFS over TCP is not supported");
  1363. goto fail;
  1364. }
  1365. fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  1366. } else
  1367. fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1368. if (fsock < 0) {
  1369. bb_perror_msg("nfs socket");
  1370. goto fail;
  1371. }
  1372. if (bindresvport(fsock, 0) < 0) {
  1373. bb_perror_msg("nfs bindresvport");
  1374. goto fail;
  1375. }
  1376. if (port == 0) {
  1377. server_addr.sin_port = PMAPPORT;
  1378. port = pmap_getport(&server_addr, nfsprog, nfsvers,
  1379. tcp ? IPPROTO_TCP : IPPROTO_UDP);
  1380. if (port == 0)
  1381. port = NFS_PORT;
  1382. }
  1383. server_addr.sin_port = htons(port);
  1384. /* Prepare data structure for kernel */
  1385. data.fd = fsock;
  1386. memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
  1387. strncpy(data.hostname, hostname, sizeof(data.hostname));
  1388. /* Clean up */
  1389. auth_destroy(mclient->cl_auth);
  1390. clnt_destroy(mclient);
  1391. close(msock);
  1392. msock = -1;
  1393. if (bg) {
  1394. /* We must wait until mount directory is available */
  1395. struct stat statbuf;
  1396. int delay = 1;
  1397. while (stat(mp->mnt_dir, &statbuf) == -1) {
  1398. if (!daemonized) {
  1399. daemonized = daemonize();
  1400. if (daemonized <= 0) { /* parent or error */
  1401. /* FIXME: parent doesn't close fsock - ??! */
  1402. retval = -daemonized;
  1403. goto ret;
  1404. }
  1405. }
  1406. sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
  1407. delay *= 2;
  1408. if (delay > 30)
  1409. delay = 30;
  1410. }
  1411. }
  1412. /* Perform actual mount */
  1413. do_mount:
  1414. mp->mnt_type = (char*)"nfs";
  1415. retval = mount_it_now(mp, vfsflags, (char*)&data);
  1416. goto ret;
  1417. /* Abort */
  1418. fail:
  1419. if (msock >= 0) {
  1420. if (mclient) {
  1421. auth_destroy(mclient->cl_auth);
  1422. clnt_destroy(mclient);
  1423. }
  1424. close(msock);
  1425. }
  1426. if (fsock >= 0)
  1427. close(fsock);
  1428. ret:
  1429. free(hostname);
  1430. free(mounthost);
  1431. free(filteropts);
  1432. return retval;
  1433. }
  1434. #else // !ENABLE_FEATURE_MOUNT_NFS
  1435. // Never called. Call should be optimized out.
  1436. int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
  1437. #endif // !ENABLE_FEATURE_MOUNT_NFS
  1438. // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
  1439. // type detection. Returns 0 for success, nonzero for failure.
  1440. // NB: mp->xxx fields may be trashed on exit
  1441. static int singlemount(struct mntent *mp, int ignore_busy)
  1442. {
  1443. int rc = -1;
  1444. long vfsflags;
  1445. char *loopFile = NULL, *filteropts = NULL;
  1446. llist_t *fl = NULL;
  1447. struct stat st;
  1448. errno = 0;
  1449. vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
  1450. // Treat fstype "auto" as unspecified
  1451. if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
  1452. mp->mnt_type = NULL;
  1453. // Might this be a virtual filesystem?
  1454. if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
  1455. char *args[35];
  1456. char *s;
  1457. int n;
  1458. // fsname: "cmd#arg1#arg2..."
  1459. // WARNING: allows execution of arbitrary commands!
  1460. // Try "mount 'sh#-c#sh' bogus_dir".
  1461. // It is safe ONLY because non-root
  1462. // cannot use two-argument mount command
  1463. // and using one-argument "mount 'sh#-c#sh'" doesn't work:
  1464. // "mount: can't find sh#-c#sh in /etc/fstab"
  1465. // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
  1466. s = mp->mnt_fsname;
  1467. n = 0;
  1468. args[n++] = s;
  1469. while (*s && n < 35 - 2) {
  1470. if (*s++ == '#' && *s != '#') {
  1471. s[-1] = '\0';
  1472. args[n++] = s;
  1473. }
  1474. }
  1475. args[n++] = mp->mnt_dir;
  1476. args[n] = NULL;
  1477. rc = wait4pid(xspawn(args));
  1478. goto report_error;
  1479. }
  1480. // Might this be an CIFS filesystem?
  1481. if (ENABLE_FEATURE_MOUNT_CIFS
  1482. && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
  1483. && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
  1484. && mp->mnt_fsname[0] == mp->mnt_fsname[1]
  1485. ) {
  1486. int len;
  1487. char c;
  1488. len_and_sockaddr *lsa;
  1489. char *hostname, *dotted, *ip;
  1490. hostname = mp->mnt_fsname + 2;
  1491. len = strcspn(hostname, "/\\");
  1492. if (len == 0 || hostname[len] == '\0')
  1493. goto report_error;
  1494. c = hostname[len];
  1495. hostname[len] = '\0';
  1496. lsa = host2sockaddr(hostname, 0);
  1497. hostname[len] = c;
  1498. if (!lsa)
  1499. goto report_error;
  1500. // Insert "ip=..." option into options
  1501. dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
  1502. if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
  1503. ip = xasprintf("ip=%s", dotted);
  1504. if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
  1505. parse_mount_options(ip, &filteropts);
  1506. if (ENABLE_FEATURE_CLEAN_UP) free(ip);
  1507. // "-o mand" is required [why?]
  1508. vfsflags |= MS_MANDLOCK;
  1509. mp->mnt_type = (char*)"cifs";
  1510. rc = mount_it_now(mp, vfsflags, filteropts);
  1511. goto report_error;
  1512. }
  1513. // Might this be an NFS filesystem?
  1514. if (ENABLE_FEATURE_MOUNT_NFS
  1515. && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
  1516. && strchr(mp->mnt_fsname, ':') != NULL
  1517. ) {
  1518. rc = nfsmount(mp, vfsflags, filteropts);
  1519. goto report_error;
  1520. }
  1521. // Look at the file. (Not found isn't a failure for remount, or for
  1522. // a synthetic filesystem like proc or sysfs.)
  1523. // (We use stat, not lstat, in order to allow
  1524. // mount symlink_to_file_or_blkdev dir)
  1525. if (!stat(mp->mnt_fsname, &st)
  1526. && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
  1527. ) {
  1528. // Do we need to allocate a loopback device for it?
  1529. if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
  1530. loopFile = bb_simplify_path(mp->mnt_fsname);
  1531. mp->mnt_fsname = NULL; // will receive malloced loop dev name
  1532. if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
  1533. if (errno == EPERM || errno == EACCES)
  1534. bb_error_msg(bb_msg_perm_denied_are_you_root);
  1535. else
  1536. bb_perror_msg("can't setup loop device");
  1537. return errno;
  1538. }
  1539. // Autodetect bind mounts
  1540. } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
  1541. vfsflags |= MS_BIND;
  1542. }
  1543. // If we know the fstype (or don't need to), jump straight
  1544. // to the actual mount.
  1545. if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
  1546. rc = mount_it_now(mp, vfsflags, filteropts);
  1547. else {
  1548. // Loop through filesystem types until mount succeeds
  1549. // or we run out
  1550. // Initialize list of block backed filesystems.
  1551. // This has to be done here so that during "mount -a",
  1552. // mounts after /proc shows up can autodetect.
  1553. if (!fslist) {
  1554. fslist = get_block_backed_filesystems();
  1555. if (ENABLE_FEATURE_CLEAN_UP && fslist)
  1556. atexit(delete_block_backed_filesystems);
  1557. }
  1558. for (fl = fslist; fl; fl = fl->link) {
  1559. mp->mnt_type = fl->data;
  1560. rc = mount_it_now(mp, vfsflags, filteropts);
  1561. if (!rc)
  1562. break;
  1563. }
  1564. }
  1565. // If mount failed, clean up loop file (if any).
  1566. if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
  1567. del_loop(mp->mnt_fsname);
  1568. if (ENABLE_FEATURE_CLEAN_UP) {
  1569. free(loopFile);
  1570. free(mp->mnt_fsname);
  1571. }
  1572. }
  1573. report_error:
  1574. if (ENABLE_FEATURE_CLEAN_UP)
  1575. free(filteropts);
  1576. if (errno == EBUSY && ignore_busy)
  1577. return 0;
  1578. if (rc < 0)
  1579. bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
  1580. return rc;
  1581. }
  1582. // -O support
  1583. // -O interprets a list of filter options which select whether a mount
  1584. // point will be mounted: only mounts with options matching *all* filtering
  1585. // options will be selected.
  1586. // By default each -O filter option must be present in the list of mount
  1587. // options, but if it is prefixed by "no" then it must be absent.
  1588. // For example,
  1589. // -O a,nob,c matches -o a,c but fails to match -o a,b,c
  1590. // (and also fails to match -o a because -o c is absent).
  1591. //
  1592. // It is different from -t in that each option is matched exactly; a leading
  1593. // "no" at the beginning of one option does not negate the rest.
  1594. static int match_opt(const char *fs_opt_in, const char *O_opt)
  1595. {
  1596. if (!O_opt)
  1597. return 1;
  1598. while (*O_opt) {
  1599. const char *fs_opt = fs_opt_in;
  1600. int O_len;
  1601. int match;
  1602. // If option begins with "no" then treat as an inverted match:
  1603. // matching is a failure
  1604. match = 0;
  1605. if (O_opt[0] == 'n' && O_opt[1] == 'o') {
  1606. match = 1;
  1607. O_opt += 2;
  1608. }
  1609. // Isolate the current O option
  1610. O_len = strchrnul(O_opt, ',') - O_opt;
  1611. // Check for a match against existing options
  1612. while (1) {
  1613. if (strncmp(fs_opt, O_opt, O_len) == 0
  1614. && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
  1615. ) {
  1616. if (match)
  1617. return 0; // "no" prefix, but option found
  1618. match = 1; // current O option found, go check next one
  1619. break;
  1620. }
  1621. fs_opt = strchr(fs_opt, ',');
  1622. if (!fs_opt)
  1623. break;
  1624. fs_opt++;
  1625. }
  1626. if (match == 0)
  1627. return 0; // match wanted but not found
  1628. if (O_opt[O_len] == '\0') // end?
  1629. break;
  1630. // Step to the next O option
  1631. O_opt += O_len + 1;
  1632. }
  1633. // If we get here then everything matched
  1634. return 1;
  1635. }
  1636. // Parse options, if necessary parse fstab/mtab, and call singlemount for
  1637. // each directory to be mounted.
  1638. int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  1639. int mount_main(int argc UNUSED_PARAM, char **argv)
  1640. {
  1641. char *cmdopts = xzalloc(1);
  1642. char *fstype = NULL;
  1643. char *O_optmatch = NULL;
  1644. char *storage_path;
  1645. llist_t *lst_o = NULL;
  1646. const char *fstabname;
  1647. FILE *fstab;
  1648. int i, j;
  1649. int rc = EXIT_SUCCESS;
  1650. unsigned opt;
  1651. struct mntent mtpair[2], *mtcur = mtpair;
  1652. IF_NOT_DESKTOP(const int nonroot = 0;)
  1653. IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
  1654. // Parse long options, like --bind and --move. Note that -o option
  1655. // and --option are synonymous. Yes, this means --remount,rw works.
  1656. for (i = j = 1; argv[i]; i++) {
  1657. if (argv[i][0] == '-' && argv[i][1] == '-')
  1658. append_mount_options(&cmdopts, argv[i] + 2);
  1659. else
  1660. argv[j++] = argv[i];
  1661. }
  1662. argv[j] = NULL;
  1663. // Parse remaining options
  1664. // Max 2 params; -o is a list, -v is a counter
  1665. opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
  1666. opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
  1667. IF_FEATURE_MOUNT_VERBOSE(, &verbose));
  1668. while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
  1669. if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
  1670. if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
  1671. argv += optind;
  1672. // If we have no arguments, show currently mounted filesystems
  1673. if (!argv[0]) {
  1674. if (!(opt & OPT_a)) {
  1675. FILE *mountTable = setmntent(bb_path_mtab_file, "r");
  1676. if (!mountTable)
  1677. bb_error_msg_and_die("no %s", bb_path_mtab_file);
  1678. while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
  1679. GETMNTENT_BUFSIZE))
  1680. {
  1681. // Don't show rootfs. FIXME: why??
  1682. // util-linux 2.12a happily shows rootfs...
  1683. //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
  1684. if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
  1685. printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
  1686. mtpair->mnt_dir, mtpair->mnt_type,
  1687. mtpair->mnt_opts);
  1688. }
  1689. if (ENABLE_FEATURE_CLEAN_UP)
  1690. endmntent(mountTable);
  1691. return EXIT_SUCCESS;
  1692. }
  1693. storage_path = NULL;
  1694. } else {
  1695. // When we have two arguments, the second is the directory and we can
  1696. // skip looking at fstab entirely. We can always abspath() the directory
  1697. // argument when we get it.
  1698. if (argv[1]) {
  1699. if (nonroot)
  1700. bb_error_msg_and_die(bb_msg_you_must_be_root);
  1701. mtpair->mnt_fsname = argv[0];
  1702. mtpair->mnt_dir = argv[1];
  1703. mtpair->mnt_type = fstype;
  1704. mtpair->mnt_opts = cmdopts;
  1705. resolve_mount_spec(&mtpair->mnt_fsname);
  1706. rc = singlemount(mtpair, /*ignore_busy:*/ 0);
  1707. return rc;
  1708. }
  1709. storage_path = bb_simplify_path(argv[0]); // malloced
  1710. }
  1711. // Past this point, we are handling either "mount -a [opts]"
  1712. // or "mount [opts] single_param"
  1713. i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
  1714. if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
  1715. bb_error_msg_and_die(bb_msg_you_must_be_root);
  1716. // If we have a shared subtree flag, don't worry about fstab or mtab.
  1717. if (ENABLE_FEATURE_MOUNT_FLAGS
  1718. && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
  1719. ) {
  1720. // verbose_mount(source, target, type, flags, data)
  1721. rc = verbose_mount("", argv[0], "", i, "");
  1722. if (rc)
  1723. bb_simple_perror_msg_and_die(argv[0]);
  1724. return rc;
  1725. }
  1726. // Open either fstab or mtab
  1727. fstabname = "/etc/fstab";
  1728. if (i & MS_REMOUNT) {
  1729. // WARNING. I am not sure this matches util-linux's
  1730. // behavior. It's possible util-linux does not
  1731. // take -o opts from mtab (takes only mount source).
  1732. fstabname = bb_path_mtab_file;
  1733. }
  1734. fstab = setmntent(fstabname, "r");
  1735. if (!fstab)
  1736. bb_perror_msg_and_die("can't read %s", fstabname);
  1737. // Loop through entries until we find what we're looking for
  1738. memset(mtpair, 0, sizeof(mtpair));
  1739. for (;;) {
  1740. struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
  1741. // Get next fstab entry
  1742. if (!getmntent_r(fstab, mtcur, getmntent_buf
  1743. + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
  1744. GETMNTENT_BUFSIZE/2)
  1745. ) { // End of fstab/mtab is reached
  1746. mtcur = mtother; // the thing we found last time
  1747. break;
  1748. }
  1749. // If we're trying to mount something specific and this isn't it,
  1750. // skip it. Note we must match the exact text in fstab (ala
  1751. // "proc") or a full path from root
  1752. if (argv[0]) {
  1753. // Is this what we're looking for?
  1754. if (strcmp(argv[0], mtcur->mnt_fsname) != 0
  1755. && strcmp(storage_path, mtcur->mnt_fsname) != 0
  1756. && strcmp(argv[0], mtcur->mnt_dir) != 0
  1757. && strcmp(storage_path, mtcur->mnt_dir) != 0
  1758. ) {
  1759. continue; // no
  1760. }
  1761. // Remember this entry. Something later may have
  1762. // overmounted it, and we want the _last_ match.
  1763. mtcur = mtother;
  1764. // If we're mounting all
  1765. } else {
  1766. struct mntent *mp;
  1767. // No, mount -a won't mount anything,
  1768. // even user mounts, for mere humans
  1769. if (nonroot)
  1770. bb_error_msg_and_die(bb_msg_you_must_be_root);
  1771. // Does type match? (NULL matches always)
  1772. if (!match_fstype(mtcur, fstype))
  1773. continue;
  1774. // Skip noauto and swap anyway
  1775. if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
  1776. // swap is bogus "fstype", parse_mount_options can't check fstypes
  1777. || strcasecmp(mtcur->mnt_type, "swap") == 0
  1778. ) {
  1779. continue;
  1780. }
  1781. // Does (at least one) option match?
  1782. // (NULL matches always)
  1783. if (!match_opt(mtcur->mnt_opts, O_optmatch))
  1784. continue;
  1785. resolve_mount_spec(&mtcur->mnt_fsname);
  1786. // NFS mounts want this to be xrealloc-able
  1787. mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
  1788. // If nothing is mounted on this directory...
  1789. // (otherwise repeated "mount -a" mounts everything again)
  1790. mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
  1791. // We do not check fsname match of found mount point -
  1792. // "/" may have fsname of "/dev/root" while fstab
  1793. // says "/dev/something_else".
  1794. if (mp) {
  1795. if (verbose) {
  1796. bb_error_msg("according to %s, "
  1797. "%s is already mounted on %s",
  1798. bb_path_mtab_file,
  1799. mp->mnt_fsname, mp->mnt_dir);
  1800. }
  1801. } else {
  1802. // ...mount this thing
  1803. if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
  1804. // Count number of failed mounts
  1805. rc++;
  1806. }
  1807. }
  1808. free(mtcur->mnt_opts);
  1809. }
  1810. }
  1811. // End of fstab/mtab is reached.
  1812. // Were we looking for something specific?
  1813. if (argv[0]) { // yes
  1814. long l;
  1815. // If we didn't find anything, complain
  1816. if (!mtcur->mnt_fsname)
  1817. bb_error_msg_and_die("can't find %s in %s",
  1818. argv[0], fstabname);
  1819. // What happens when we try to "mount swap_partition"?
  1820. // (fstab containts "swap_partition swap swap defaults 0 0")
  1821. // util-linux-ng 2.13.1 does this:
  1822. // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
  1823. // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
  1824. // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
  1825. // write(2, "mount: mount point swap does not exist\n", 39) = 39
  1826. // exit_group(32) = ?
  1827. #if 0
  1828. // In case we want to simply skip swap partitions:
  1829. l = parse_mount_options(mtcur->mnt_opts, NULL);
  1830. if ((l & MOUNT_SWAP)
  1831. // swap is bogus "fstype", parse_mount_options can't check fstypes
  1832. || strcasecmp(mtcur->mnt_type, "swap") == 0
  1833. ) {
  1834. goto ret;
  1835. }
  1836. #endif
  1837. if (nonroot) {
  1838. // fstab must have "users" or "user"
  1839. l = parse_mount_options(mtcur->mnt_opts, NULL);
  1840. if (!(l & MOUNT_USERS))
  1841. bb_error_msg_and_die(bb_msg_you_must_be_root);
  1842. }
  1843. //util-linux-2.12 does not do this check.
  1844. //// If nothing is mounted on this directory...
  1845. //// (otherwise repeated "mount FOO" mounts FOO again)
  1846. //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
  1847. //if (mp) {
  1848. // bb_error_msg("according to %s, "
  1849. // "%s is already mounted on %s",
  1850. // bb_path_mtab_file,
  1851. // mp->mnt_fsname, mp->mnt_dir);
  1852. //} else {
  1853. // ...mount the last thing we found
  1854. mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
  1855. append_mount_options(&(mtcur->mnt_opts), cmdopts);
  1856. resolve_mount_spec(&mtpair->mnt_fsname);
  1857. rc = singlemount(mtcur, /*ignore_busy:*/ 0);
  1858. if (ENABLE_FEATURE_CLEAN_UP)
  1859. free(mtcur->mnt_opts);
  1860. //}
  1861. }
  1862. //ret:
  1863. if (ENABLE_FEATURE_CLEAN_UP)
  1864. endmntent(fstab);
  1865. if (ENABLE_FEATURE_CLEAN_UP) {
  1866. free(storage_path);
  1867. free(cmdopts);
  1868. }
  1869. //TODO: exitcode should be ORed mask of (from "man mount"):
  1870. // 0 success
  1871. // 1 incorrect invocation or permissions
  1872. // 2 system error (out of memory, cannot fork, no more loop devices)
  1873. // 4 internal mount bug or missing nfs support in mount
  1874. // 8 user interrupt
  1875. //16 problems writing or locking /etc/mtab
  1876. //32 mount failure
  1877. //64 some mount succeeded
  1878. return rc;
  1879. }