nfsmount.c 25 KB

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