nfsmount.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * nfsmount.c -- Linux NFS mount
  4. * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2, or (at your option)
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
  17. * numbers to be specified on the command line.
  18. *
  19. * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
  20. * Omit the call to connect() for Linux version 1.3.11 or later.
  21. *
  22. * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
  23. * Implemented the "bg", "fg" and "retry" mount options for NFS.
  24. *
  25. * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
  26. * - added Native Language Support
  27. *
  28. * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
  29. * plus NFSv3 stuff.
  30. */
  31. /*
  32. * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
  33. */
  34. #include <unistd.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <errno.h>
  38. #include <netdb.h>
  39. #include <sys/socket.h>
  40. #include <time.h>
  41. #include <sys/utsname.h>
  42. #include <netinet/in.h>
  43. #include <arpa/inet.h>
  44. #include <stdlib.h>
  45. #include "busybox.h"
  46. #undef TRUE
  47. #undef FALSE
  48. #include <rpc/rpc.h>
  49. #include <rpc/pmap_prot.h>
  50. #include <rpc/pmap_clnt.h>
  51. #include "nfsmount.h"
  52. /*
  53. * NFS stats. The good thing with these values is that NFSv3 errors are
  54. * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
  55. * no-one uses anyway), so we can happily mix code as long as we make sure
  56. * no NFSv3 errors are returned to NFSv2 clients.
  57. * Error codes that have a `--' in the v2 column are not part of the
  58. * standard, but seem to be widely used nevertheless.
  59. */
  60. enum nfs_stat {
  61. NFS_OK = 0, /* v2 v3 */
  62. NFSERR_PERM = 1, /* v2 v3 */
  63. NFSERR_NOENT = 2, /* v2 v3 */
  64. NFSERR_IO = 5, /* v2 v3 */
  65. NFSERR_NXIO = 6, /* v2 v3 */
  66. NFSERR_EAGAIN = 11, /* v2 v3 */
  67. NFSERR_ACCES = 13, /* v2 v3 */
  68. NFSERR_EXIST = 17, /* v2 v3 */
  69. NFSERR_XDEV = 18, /* v3 */
  70. NFSERR_NODEV = 19, /* v2 v3 */
  71. NFSERR_NOTDIR = 20, /* v2 v3 */
  72. NFSERR_ISDIR = 21, /* v2 v3 */
  73. NFSERR_INVAL = 22, /* v2 v3 that Sun forgot */
  74. NFSERR_FBIG = 27, /* v2 v3 */
  75. NFSERR_NOSPC = 28, /* v2 v3 */
  76. NFSERR_ROFS = 30, /* v2 v3 */
  77. NFSERR_MLINK = 31, /* v3 */
  78. NFSERR_OPNOTSUPP = 45, /* v2 v3 */
  79. NFSERR_NAMETOOLONG = 63, /* v2 v3 */
  80. NFSERR_NOTEMPTY = 66, /* v2 v3 */
  81. NFSERR_DQUOT = 69, /* v2 v3 */
  82. NFSERR_STALE = 70, /* v2 v3 */
  83. NFSERR_REMOTE = 71, /* v2 v3 */
  84. NFSERR_WFLUSH = 99, /* v2 */
  85. NFSERR_BADHANDLE = 10001, /* v3 */
  86. NFSERR_NOT_SYNC = 10002, /* v3 */
  87. NFSERR_BAD_COOKIE = 10003, /* v3 */
  88. NFSERR_NOTSUPP = 10004, /* v3 */
  89. NFSERR_TOOSMALL = 10005, /* v3 */
  90. NFSERR_SERVERFAULT = 10006, /* v3 */
  91. NFSERR_BADTYPE = 10007, /* v3 */
  92. NFSERR_JUKEBOX = 10008 /* v3 */
  93. };
  94. #define NFS_PROGRAM 100003
  95. #ifndef NFS_FHSIZE
  96. static const int NFS_FHSIZE = 32;
  97. #endif
  98. #ifndef NFS_PORT
  99. static const int NFS_PORT = 2049;
  100. #endif
  101. /* Disable the nls stuff */
  102. # undef bindtextdomain
  103. # define bindtextdomain(Domain, Directory) /* empty */
  104. # undef textdomain
  105. # define textdomain(Domain) /* empty */
  106. # define _(Text) (Text)
  107. # define N_(Text) (Text)
  108. static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
  109. static const int MS_RDONLY = 1; /* Mount read-only */
  110. static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */
  111. static const int MS_NODEV = 4; /* Disallow access to device special files */
  112. static const int MS_NOEXEC = 8; /* Disallow program execution */
  113. static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */
  114. static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */
  115. static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */
  116. static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */
  117. static const int S_APPEND = 256; /* Append-only file */
  118. static const int S_IMMUTABLE = 512; /* Immutable file */
  119. static const int MS_NOATIME = 1024; /* Do not update access times. */
  120. static const int MS_NODIRATIME = 2048; /* Do not update directory access times */
  121. /*
  122. * We want to be able to compile mount on old kernels in such a way
  123. * that the binary will work well on more recent kernels.
  124. * Thus, if necessary we teach nfsmount.c the structure of new fields
  125. * that will come later.
  126. *
  127. * Moreover, the new kernel includes conflict with glibc includes
  128. * so it is easiest to ignore the kernel altogether (at compile time).
  129. */
  130. /* NOTE: Do not make this into a 'static const int' because the pre-processor
  131. * needs to test this value in some #if statements. */
  132. #define NFS_MOUNT_VERSION 4
  133. struct nfs2_fh {
  134. char data[32];
  135. };
  136. struct nfs3_fh {
  137. unsigned short size;
  138. unsigned char data[64];
  139. };
  140. struct nfs_mount_data {
  141. int version; /* 1 */
  142. int fd; /* 1 */
  143. struct nfs2_fh old_root; /* 1 */
  144. int flags; /* 1 */
  145. int rsize; /* 1 */
  146. int wsize; /* 1 */
  147. int timeo; /* 1 */
  148. int retrans; /* 1 */
  149. int acregmin; /* 1 */
  150. int acregmax; /* 1 */
  151. int acdirmin; /* 1 */
  152. int acdirmax; /* 1 */
  153. struct sockaddr_in addr; /* 1 */
  154. char hostname[256]; /* 1 */
  155. int namlen; /* 2 */
  156. unsigned int bsize; /* 3 */
  157. struct nfs3_fh root; /* 4 */
  158. };
  159. /* bits in the flags field */
  160. static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */
  161. static const int NFS_MOUNT_INTR = 0x0002; /* 1 */
  162. static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */
  163. static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */
  164. static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */
  165. static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */
  166. static const int NFS_MOUNT_TCP = 0x0040; /* 2 */
  167. static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */
  168. static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */
  169. static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */
  170. #define UTIL_LINUX_VERSION "2.10m"
  171. #define util_linux_version "util-linux-2.10m"
  172. #define HAVE_inet_aton
  173. #define HAVE_scsi_h
  174. #define HAVE_blkpg_h
  175. #define HAVE_kd_h
  176. #define HAVE_termcap
  177. #define HAVE_locale_h
  178. #define HAVE_libintl_h
  179. #define ENABLE_NLS
  180. #define HAVE_langinfo_h
  181. #define HAVE_progname
  182. #define HAVE_openpty
  183. #define HAVE_nanosleep
  184. #define HAVE_personality
  185. #define HAVE_tm_gmtoff
  186. static char *nfs_strerror(int status);
  187. #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
  188. #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
  189. static const int EX_FAIL = 32; /* mount failure */
  190. static const int EX_BG = 256; /* retry in background (internal only) */
  191. /*
  192. * nfs_mount_version according to the sources seen at compile time.
  193. */
  194. static int nfs_mount_version;
  195. /*
  196. * Unfortunately, the kernel prints annoying console messages
  197. * in case of an unexpected nfs mount version (instead of
  198. * just returning some error). Therefore we'll have to try
  199. * and figure out what version the kernel expects.
  200. *
  201. * Variables:
  202. * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
  203. * NFS_MOUNT_VERSION: these nfsmount sources at compile time
  204. * nfs_mount_version: version this source and running kernel can handle
  205. */
  206. static void
  207. find_kernel_nfs_mount_version(void)
  208. {
  209. static int kernel_version = 0;
  210. if (kernel_version)
  211. return;
  212. nfs_mount_version = NFS_MOUNT_VERSION; /* default */
  213. kernel_version = get_kernel_revision();
  214. if (kernel_version) {
  215. if (kernel_version < MAKE_VERSION(2,1,32))
  216. nfs_mount_version = 1;
  217. else if (kernel_version < MAKE_VERSION(2,2,18) ||
  218. (kernel_version >= MAKE_VERSION(2,3,0) &&
  219. kernel_version < MAKE_VERSION(2,3,99)))
  220. nfs_mount_version = 3;
  221. else
  222. nfs_mount_version = 4; /* since 2.3.99pre4 */
  223. }
  224. if (nfs_mount_version > NFS_MOUNT_VERSION)
  225. nfs_mount_version = NFS_MOUNT_VERSION;
  226. }
  227. static struct pmap *
  228. get_mountport(struct sockaddr_in *server_addr,
  229. long unsigned prog,
  230. long unsigned version,
  231. long unsigned proto,
  232. long unsigned port)
  233. {
  234. struct pmaplist *pmap;
  235. static struct pmap p = {0, 0, 0, 0};
  236. server_addr->sin_port = PMAPPORT;
  237. pmap = pmap_getmaps(server_addr);
  238. if (version > MAX_NFSPROT)
  239. version = MAX_NFSPROT;
  240. if (!prog)
  241. prog = MOUNTPROG;
  242. p.pm_prog = prog;
  243. p.pm_vers = version;
  244. p.pm_prot = proto;
  245. p.pm_port = port;
  246. while (pmap) {
  247. if (pmap->pml_map.pm_prog != prog)
  248. goto next;
  249. if (!version && p.pm_vers > pmap->pml_map.pm_vers)
  250. goto next;
  251. if (version > 2 && pmap->pml_map.pm_vers != version)
  252. goto next;
  253. if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
  254. goto next;
  255. if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
  256. (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
  257. (port && pmap->pml_map.pm_port != port))
  258. goto next;
  259. memcpy(&p, &pmap->pml_map, sizeof(p));
  260. next:
  261. pmap = pmap->pml_next;
  262. }
  263. if (!p.pm_vers)
  264. p.pm_vers = MOUNTVERS;
  265. if (!p.pm_port)
  266. p.pm_port = MOUNTPORT;
  267. if (!p.pm_prot)
  268. p.pm_prot = IPPROTO_TCP;
  269. return &p;
  270. }
  271. int nfsmount(const char *spec, const char *node, int *flags,
  272. char **extra_opts, char **mount_opts, int running_bg)
  273. {
  274. static char *prev_bg_host;
  275. char hostdir[1024];
  276. CLIENT *mclient;
  277. char *hostname;
  278. char *pathname;
  279. char *old_opts;
  280. char *mounthost=NULL;
  281. char new_opts[1024];
  282. struct timeval total_timeout;
  283. enum clnt_stat clnt_stat;
  284. struct nfs_mount_data data;
  285. char *opt, *opteq;
  286. int val;
  287. struct hostent *hp;
  288. struct sockaddr_in server_addr;
  289. struct sockaddr_in mount_server_addr;
  290. struct pmap* pm_mnt;
  291. int msock, fsock;
  292. struct timeval retry_timeout;
  293. union {
  294. struct fhstatus nfsv2;
  295. struct mountres3 nfsv3;
  296. } status;
  297. struct stat statbuf;
  298. char *s;
  299. int port;
  300. int mountport;
  301. int proto;
  302. int bg;
  303. int soft;
  304. int intr;
  305. int posix;
  306. int nocto;
  307. int noac;
  308. int nolock;
  309. int retry;
  310. int tcp;
  311. int mountprog;
  312. int mountvers;
  313. int nfsprog;
  314. int nfsvers;
  315. int retval;
  316. time_t t;
  317. time_t prevt;
  318. time_t timeout;
  319. find_kernel_nfs_mount_version();
  320. retval = EX_FAIL;
  321. msock = fsock = -1;
  322. mclient = NULL;
  323. if (strlen(spec) >= sizeof(hostdir)) {
  324. bb_error_msg("excessively long host:dir argument");
  325. goto fail;
  326. }
  327. strcpy(hostdir, spec);
  328. if ((s = strchr(hostdir, ':'))) {
  329. hostname = hostdir;
  330. pathname = s + 1;
  331. *s = '\0';
  332. /* Ignore all but first hostname in replicated mounts
  333. until they can be fully supported. (mack@sgi.com) */
  334. if ((s = strchr(hostdir, ','))) {
  335. *s = '\0';
  336. bb_error_msg("warning: multiple hostnames not supported");
  337. }
  338. } else {
  339. bb_error_msg("directory to mount not in host:dir format");
  340. goto fail;
  341. }
  342. server_addr.sin_family = AF_INET;
  343. #ifdef HAVE_inet_aton
  344. if (!inet_aton(hostname, &server_addr.sin_addr))
  345. #endif
  346. {
  347. if ((hp = gethostbyname(hostname)) == NULL) {
  348. bb_herror_msg("%s", hostname);
  349. goto fail;
  350. } else {
  351. if (hp->h_length > sizeof(struct in_addr)) {
  352. bb_error_msg("got bad hp->h_length");
  353. hp->h_length = sizeof(struct in_addr);
  354. }
  355. memcpy(&server_addr.sin_addr,
  356. hp->h_addr, hp->h_length);
  357. }
  358. }
  359. memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
  360. /* add IP address to mtab options for use when unmounting */
  361. s = inet_ntoa(server_addr.sin_addr);
  362. old_opts = *extra_opts;
  363. if (!old_opts)
  364. old_opts = "";
  365. if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
  366. bb_error_msg("excessively long option argument");
  367. goto fail;
  368. }
  369. sprintf(new_opts, "%s%saddr=%s",
  370. old_opts, *old_opts ? "," : "", s);
  371. *extra_opts = bb_xstrdup(new_opts);
  372. /* Set default options.
  373. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
  374. * let the kernel decide.
  375. * timeo is filled in after we know whether it'll be TCP or UDP. */
  376. memset(&data, 0, sizeof(data));
  377. data.retrans = 3;
  378. data.acregmin = 3;
  379. data.acregmax = 60;
  380. data.acdirmin = 30;
  381. data.acdirmax = 60;
  382. #if NFS_MOUNT_VERSION >= 2
  383. data.namlen = NAME_MAX;
  384. #endif
  385. bg = 0;
  386. soft = 0;
  387. intr = 0;
  388. posix = 0;
  389. nocto = 0;
  390. nolock = 0;
  391. noac = 0;
  392. retry = 10000; /* 10000 minutes ~ 1 week */
  393. tcp = 0;
  394. mountprog = MOUNTPROG;
  395. mountvers = 0;
  396. port = 0;
  397. mountport = 0;
  398. nfsprog = NFS_PROGRAM;
  399. nfsvers = 0;
  400. /* parse options */
  401. for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
  402. if ((opteq = strchr(opt, '='))) {
  403. val = atoi(opteq + 1);
  404. *opteq = '\0';
  405. if (!strcmp(opt, "rsize"))
  406. data.rsize = val;
  407. else if (!strcmp(opt, "wsize"))
  408. data.wsize = val;
  409. else if (!strcmp(opt, "timeo"))
  410. data.timeo = val;
  411. else if (!strcmp(opt, "retrans"))
  412. data.retrans = val;
  413. else if (!strcmp(opt, "acregmin"))
  414. data.acregmin = val;
  415. else if (!strcmp(opt, "acregmax"))
  416. data.acregmax = val;
  417. else if (!strcmp(opt, "acdirmin"))
  418. data.acdirmin = val;
  419. else if (!strcmp(opt, "acdirmax"))
  420. data.acdirmax = val;
  421. else if (!strcmp(opt, "actimeo")) {
  422. data.acregmin = val;
  423. data.acregmax = val;
  424. data.acdirmin = val;
  425. data.acdirmax = val;
  426. }
  427. else if (!strcmp(opt, "retry"))
  428. retry = val;
  429. else if (!strcmp(opt, "port"))
  430. port = val;
  431. else if (!strcmp(opt, "mountport"))
  432. mountport = val;
  433. else if (!strcmp(opt, "mounthost"))
  434. mounthost=bb_xstrndup(opteq+1,
  435. strcspn(opteq+1," \t\n\r,"));
  436. else if (!strcmp(opt, "mountprog"))
  437. mountprog = val;
  438. else if (!strcmp(opt, "mountvers"))
  439. mountvers = val;
  440. else if (!strcmp(opt, "nfsprog"))
  441. nfsprog = val;
  442. else if (!strcmp(opt, "nfsvers") ||
  443. !strcmp(opt, "vers"))
  444. nfsvers = val;
  445. else if (!strcmp(opt, "proto")) {
  446. if (!strncmp(opteq+1, "tcp", 3))
  447. tcp = 1;
  448. else if (!strncmp(opteq+1, "udp", 3))
  449. tcp = 0;
  450. else
  451. printf(_("Warning: Unrecognized proto= option.\n"));
  452. } else if (!strcmp(opt, "namlen")) {
  453. #if NFS_MOUNT_VERSION >= 2
  454. if (nfs_mount_version >= 2)
  455. data.namlen = val;
  456. else
  457. #endif
  458. printf(_("Warning: Option namlen is not supported.\n"));
  459. } else if (!strcmp(opt, "addr"))
  460. /* ignore */;
  461. else {
  462. printf(_("unknown nfs mount parameter: "
  463. "%s=%d\n"), opt, val);
  464. goto fail;
  465. }
  466. }
  467. else {
  468. val = 1;
  469. if (!strncmp(opt, "no", 2)) {
  470. val = 0;
  471. opt += 2;
  472. }
  473. if (!strcmp(opt, "bg"))
  474. bg = val;
  475. else if (!strcmp(opt, "fg"))
  476. bg = !val;
  477. else if (!strcmp(opt, "soft"))
  478. soft = val;
  479. else if (!strcmp(opt, "hard"))
  480. soft = !val;
  481. else if (!strcmp(opt, "intr"))
  482. intr = val;
  483. else if (!strcmp(opt, "posix"))
  484. posix = val;
  485. else if (!strcmp(opt, "cto"))
  486. nocto = !val;
  487. else if (!strcmp(opt, "ac"))
  488. noac = !val;
  489. else if (!strcmp(opt, "tcp"))
  490. tcp = val;
  491. else if (!strcmp(opt, "udp"))
  492. tcp = !val;
  493. else if (!strcmp(opt, "lock")) {
  494. if (nfs_mount_version >= 3)
  495. nolock = !val;
  496. else
  497. printf(_("Warning: option nolock is not supported.\n"));
  498. } else {
  499. printf(_("unknown nfs mount option: "
  500. "%s%s\n"), val ? "" : "no", opt);
  501. goto fail;
  502. }
  503. }
  504. }
  505. proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
  506. data.flags = (soft ? NFS_MOUNT_SOFT : 0)
  507. | (intr ? NFS_MOUNT_INTR : 0)
  508. | (posix ? NFS_MOUNT_POSIX : 0)
  509. | (nocto ? NFS_MOUNT_NOCTO : 0)
  510. | (noac ? NFS_MOUNT_NOAC : 0);
  511. #if NFS_MOUNT_VERSION >= 2
  512. if (nfs_mount_version >= 2)
  513. data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
  514. #endif
  515. #if NFS_MOUNT_VERSION >= 3
  516. if (nfs_mount_version >= 3)
  517. data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
  518. #endif
  519. if (nfsvers > MAX_NFSPROT) {
  520. bb_error_msg("NFSv%d not supported!", nfsvers);
  521. return 0;
  522. }
  523. if (mountvers > MAX_NFSPROT) {
  524. bb_error_msg("NFSv%d not supported!", nfsvers);
  525. return 0;
  526. }
  527. if (nfsvers && !mountvers)
  528. mountvers = (nfsvers < 3) ? 1 : nfsvers;
  529. if (nfsvers && nfsvers < mountvers) {
  530. mountvers = nfsvers;
  531. }
  532. /* Adjust options if none specified */
  533. if (!data.timeo)
  534. data.timeo = tcp ? 70 : 7;
  535. #ifdef NFS_MOUNT_DEBUG
  536. printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
  537. data.rsize, data.wsize, data.timeo, data.retrans);
  538. printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
  539. data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
  540. printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
  541. port, bg, retry, data.flags);
  542. printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
  543. mountprog, mountvers, nfsprog, nfsvers);
  544. printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
  545. (data.flags & NFS_MOUNT_SOFT) != 0,
  546. (data.flags & NFS_MOUNT_INTR) != 0,
  547. (data.flags & NFS_MOUNT_POSIX) != 0,
  548. (data.flags & NFS_MOUNT_NOCTO) != 0,
  549. (data.flags & NFS_MOUNT_NOAC) != 0);
  550. #if NFS_MOUNT_VERSION >= 2
  551. printf("tcp = %d\n",
  552. (data.flags & NFS_MOUNT_TCP) != 0);
  553. #endif
  554. #endif
  555. data.version = nfs_mount_version;
  556. if (*flags & MS_REMOUNT)
  557. goto copy_data_and_return;
  558. /*
  559. * If the previous mount operation on the same host was
  560. * backgrounded, and the "bg" for this mount is also set,
  561. * give up immediately, to avoid the initial timeout.
  562. */
  563. if (bg && !running_bg &&
  564. prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
  565. if (retry > 0)
  566. retval = EX_BG;
  567. return retval;
  568. }
  569. /* create mount deamon client */
  570. /* See if the nfs host = mount host. */
  571. if (mounthost) {
  572. if (mounthost[0] >= '0' && mounthost[0] <= '9') {
  573. mount_server_addr.sin_family = AF_INET;
  574. mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
  575. } else {
  576. if ((hp = gethostbyname(mounthost)) == NULL) {
  577. bb_herror_msg("%s", mounthost);
  578. goto fail;
  579. } else {
  580. if (hp->h_length > sizeof(struct in_addr)) {
  581. bb_error_msg("got bad hp->h_length?");
  582. hp->h_length = sizeof(struct in_addr);
  583. }
  584. mount_server_addr.sin_family = AF_INET;
  585. memcpy(&mount_server_addr.sin_addr,
  586. hp->h_addr, hp->h_length);
  587. }
  588. }
  589. }
  590. /*
  591. * The following loop implements the mount retries. On the first
  592. * call, "running_bg" is 0. When the mount times out, and the
  593. * "bg" option is set, the exit status EX_BG will be returned.
  594. * For a backgrounded mount, there will be a second call by the
  595. * child process with "running_bg" set to 1.
  596. *
  597. * The case where the mount point is not present and the "bg"
  598. * option is set, is treated as a timeout. This is done to
  599. * support nested mounts.
  600. *
  601. * The "retry" count specified by the user is the number of
  602. * minutes to retry before giving up.
  603. *
  604. * Only the first error message will be displayed.
  605. */
  606. retry_timeout.tv_sec = 3;
  607. retry_timeout.tv_usec = 0;
  608. total_timeout.tv_sec = 20;
  609. total_timeout.tv_usec = 0;
  610. timeout = time(NULL) + 60 * retry;
  611. prevt = 0;
  612. t = 30;
  613. val = 1;
  614. for (;;) {
  615. if (bg && stat(node, &statbuf) == -1) {
  616. if (running_bg) {
  617. sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
  618. val *= 2;
  619. if (val > 30)
  620. val = 30;
  621. }
  622. } else {
  623. /* be careful not to use too many CPU cycles */
  624. if (t - prevt < 30)
  625. sleep(30);
  626. pm_mnt = get_mountport(&mount_server_addr,
  627. mountprog,
  628. mountvers,
  629. proto,
  630. mountport);
  631. /* contact the mount daemon via TCP */
  632. mount_server_addr.sin_port = htons(pm_mnt->pm_port);
  633. msock = RPC_ANYSOCK;
  634. switch (pm_mnt->pm_prot) {
  635. case IPPROTO_UDP:
  636. mclient = clntudp_create(&mount_server_addr,
  637. pm_mnt->pm_prog,
  638. pm_mnt->pm_vers,
  639. retry_timeout,
  640. &msock);
  641. if (mclient)
  642. break;
  643. mount_server_addr.sin_port = htons(pm_mnt->pm_port);
  644. msock = RPC_ANYSOCK;
  645. case IPPROTO_TCP:
  646. mclient = clnttcp_create(&mount_server_addr,
  647. pm_mnt->pm_prog,
  648. pm_mnt->pm_vers,
  649. &msock, 0, 0);
  650. break;
  651. default:
  652. mclient = 0;
  653. }
  654. if (mclient) {
  655. /* try to mount hostname:pathname */
  656. mclient->cl_auth = authunix_create_default();
  657. /* make pointers in xdr_mountres3 NULL so
  658. * that xdr_array allocates memory for us
  659. */
  660. memset(&status, 0, sizeof(status));
  661. if (pm_mnt->pm_vers == 3)
  662. clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
  663. (xdrproc_t) xdr_dirpath,
  664. (caddr_t) &pathname,
  665. (xdrproc_t) xdr_mountres3,
  666. (caddr_t) &status,
  667. total_timeout);
  668. else
  669. clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
  670. (xdrproc_t) xdr_dirpath,
  671. (caddr_t) &pathname,
  672. (xdrproc_t) xdr_fhstatus,
  673. (caddr_t) &status,
  674. total_timeout);
  675. if (clnt_stat == RPC_SUCCESS)
  676. break; /* we're done */
  677. if (errno != ECONNREFUSED) {
  678. clnt_perror(mclient, "mount");
  679. goto fail; /* don't retry */
  680. }
  681. if (!running_bg && prevt == 0)
  682. clnt_perror(mclient, "mount");
  683. auth_destroy(mclient->cl_auth);
  684. clnt_destroy(mclient);
  685. mclient = 0;
  686. close(msock);
  687. } else {
  688. if (!running_bg && prevt == 0)
  689. clnt_pcreateerror("mount");
  690. }
  691. prevt = t;
  692. }
  693. if (!bg)
  694. goto fail;
  695. if (!running_bg) {
  696. prev_bg_host = bb_xstrdup(hostname);
  697. if (retry > 0)
  698. retval = EX_BG;
  699. goto fail;
  700. }
  701. t = time(NULL);
  702. if (t >= timeout)
  703. goto fail;
  704. }
  705. nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
  706. if (nfsvers == 2) {
  707. if (status.nfsv2.fhs_status != 0) {
  708. bb_error_msg("%s:%s failed, reason given by server: %s",
  709. hostname, pathname,
  710. nfs_strerror(status.nfsv2.fhs_status));
  711. goto fail;
  712. }
  713. memcpy(data.root.data,
  714. (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
  715. NFS_FHSIZE);
  716. #if NFS_MOUNT_VERSION >= 4
  717. data.root.size = NFS_FHSIZE;
  718. memcpy(data.old_root.data,
  719. (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
  720. NFS_FHSIZE);
  721. #endif
  722. } else {
  723. #if NFS_MOUNT_VERSION >= 4
  724. fhandle3 *my_fhandle;
  725. if (status.nfsv3.fhs_status != 0) {
  726. bb_error_msg("%s:%s failed, reason given by server: %s",
  727. hostname, pathname,
  728. nfs_strerror(status.nfsv3.fhs_status));
  729. goto fail;
  730. }
  731. my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
  732. memset(data.old_root.data, 0, NFS_FHSIZE);
  733. memset(&data.root, 0, sizeof(data.root));
  734. data.root.size = my_fhandle->fhandle3_len;
  735. memcpy(data.root.data,
  736. (char *) my_fhandle->fhandle3_val,
  737. my_fhandle->fhandle3_len);
  738. data.flags |= NFS_MOUNT_VER3;
  739. #endif
  740. }
  741. /* create nfs socket for kernel */
  742. if (tcp) {
  743. if (nfs_mount_version < 3) {
  744. printf(_("NFS over TCP is not supported.\n"));
  745. goto fail;
  746. }
  747. fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  748. } else
  749. fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  750. if (fsock < 0) {
  751. perror(_("nfs socket"));
  752. goto fail;
  753. }
  754. if (bindresvport(fsock, 0) < 0) {
  755. perror(_("nfs bindresvport"));
  756. goto fail;
  757. }
  758. if (port == 0) {
  759. server_addr.sin_port = PMAPPORT;
  760. port = pmap_getport(&server_addr, nfsprog, nfsvers,
  761. tcp ? IPPROTO_TCP : IPPROTO_UDP);
  762. if (port == 0)
  763. port = NFS_PORT;
  764. #ifdef NFS_MOUNT_DEBUG
  765. else
  766. printf(_("used portmapper to find NFS port\n"));
  767. #endif
  768. }
  769. #ifdef NFS_MOUNT_DEBUG
  770. printf(_("using port %d for nfs deamon\n"), port);
  771. #endif
  772. server_addr.sin_port = htons(port);
  773. /*
  774. * connect() the socket for kernels 1.3.10 and below only,
  775. * to avoid problems with multihomed hosts.
  776. * --Swen
  777. */
  778. if (get_kernel_revision() <= 66314
  779. && connect(fsock, (struct sockaddr *) &server_addr,
  780. sizeof (server_addr)) < 0) {
  781. perror(_("nfs connect"));
  782. goto fail;
  783. }
  784. /* prepare data structure for kernel */
  785. data.fd = fsock;
  786. memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
  787. strncpy(data.hostname, hostname, sizeof(data.hostname));
  788. /* clean up */
  789. auth_destroy(mclient->cl_auth);
  790. clnt_destroy(mclient);
  791. close(msock);
  792. copy_data_and_return:
  793. *mount_opts = xrealloc(*mount_opts, sizeof(data));
  794. memcpy(*mount_opts, &data, sizeof(data));
  795. return 0;
  796. /* abort */
  797. fail:
  798. if (msock != -1) {
  799. if (mclient) {
  800. auth_destroy(mclient->cl_auth);
  801. clnt_destroy(mclient);
  802. }
  803. close(msock);
  804. }
  805. if (fsock != -1)
  806. close(fsock);
  807. return retval;
  808. }
  809. /*
  810. * We need to translate between nfs status return values and
  811. * the local errno values which may not be the same.
  812. *
  813. * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
  814. * "after #include <errno.h> the symbol errno is reserved for any use,
  815. * it cannot even be used as a struct tag or field name".
  816. */
  817. #ifndef EDQUOT
  818. #define EDQUOT ENOSPC
  819. #endif
  820. static struct {
  821. enum nfs_stat stat;
  822. int errnum;
  823. } nfs_errtbl[] = {
  824. { NFS_OK, 0 },
  825. { NFSERR_PERM, EPERM },
  826. { NFSERR_NOENT, ENOENT },
  827. { NFSERR_IO, EIO },
  828. { NFSERR_NXIO, ENXIO },
  829. { NFSERR_ACCES, EACCES },
  830. { NFSERR_EXIST, EEXIST },
  831. { NFSERR_NODEV, ENODEV },
  832. { NFSERR_NOTDIR, ENOTDIR },
  833. { NFSERR_ISDIR, EISDIR },
  834. #ifdef NFSERR_INVAL
  835. { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
  836. #endif
  837. { NFSERR_FBIG, EFBIG },
  838. { NFSERR_NOSPC, ENOSPC },
  839. { NFSERR_ROFS, EROFS },
  840. { NFSERR_NAMETOOLONG, ENAMETOOLONG },
  841. { NFSERR_NOTEMPTY, ENOTEMPTY },
  842. { NFSERR_DQUOT, EDQUOT },
  843. { NFSERR_STALE, ESTALE },
  844. #ifdef EWFLUSH
  845. { NFSERR_WFLUSH, EWFLUSH },
  846. #endif
  847. /* Throw in some NFSv3 values for even more fun (HP returns these) */
  848. { 71, EREMOTE },
  849. { -1, EIO }
  850. };
  851. static char *nfs_strerror(int status)
  852. {
  853. int i;
  854. static char buf[256];
  855. for (i = 0; nfs_errtbl[i].stat != -1; i++) {
  856. if (nfs_errtbl[i].stat == status)
  857. return strerror(nfs_errtbl[i].errnum);
  858. }
  859. sprintf(buf, _("unknown nfs status return value: %d"), status);
  860. return buf;
  861. }
  862. static bool_t
  863. xdr_fhandle (XDR *xdrs, fhandle objp)
  864. {
  865. //register int32_t *buf;
  866. if (!xdr_opaque (xdrs, objp, FHSIZE))
  867. return FALSE;
  868. return TRUE;
  869. }
  870. bool_t
  871. xdr_fhstatus (XDR *xdrs, fhstatus *objp)
  872. {
  873. //register int32_t *buf;
  874. if (!xdr_u_int (xdrs, &objp->fhs_status))
  875. return FALSE;
  876. switch (objp->fhs_status) {
  877. case 0:
  878. if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
  879. return FALSE;
  880. break;
  881. default:
  882. break;
  883. }
  884. return TRUE;
  885. }
  886. bool_t
  887. xdr_dirpath (XDR *xdrs, dirpath *objp)
  888. {
  889. //register int32_t *buf;
  890. if (!xdr_string (xdrs, objp, MNTPATHLEN))
  891. return FALSE;
  892. return TRUE;
  893. }
  894. bool_t
  895. xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
  896. {
  897. //register int32_t *buf;
  898. if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
  899. return FALSE;
  900. return TRUE;
  901. }
  902. bool_t
  903. xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
  904. {
  905. //register int32_t *buf;
  906. if (!xdr_fhandle3 (xdrs, &objp->fhandle))
  907. return FALSE;
  908. if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (unsigned int *) &objp->auth_flavours.auth_flavours_len, ~0,
  909. sizeof (int), (xdrproc_t) xdr_int))
  910. return FALSE;
  911. return TRUE;
  912. }
  913. bool_t
  914. xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
  915. {
  916. //register int32_t *buf;
  917. if (!xdr_enum (xdrs, (enum_t *) objp))
  918. return FALSE;
  919. return TRUE;
  920. }
  921. bool_t
  922. xdr_mountres3 (XDR *xdrs, mountres3 *objp)
  923. {
  924. //register int32_t *buf;
  925. if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
  926. return FALSE;
  927. switch (objp->fhs_status) {
  928. case MNT_OK:
  929. if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
  930. return FALSE;
  931. break;
  932. default:
  933. break;
  934. }
  935. return TRUE;
  936. }