mount.c 41 KB

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