3
0

mount.c 43 KB

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