mount.c 41 KB

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