2 * nfs4mount.c -- Linux NFS mount
3 * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * Note: this file based on the original nfsmount.c
17 * 2006-06-06 Amit Gud <agud@redhat.com>
18 * - Moved to nfs-utils/utils/mount from util-linux/mount.
32 #include <sys/mount.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
37 #ifdef HAVE_RPCSVC_NFS_PROT_H
38 #include <rpcsvc/nfs_prot.h>
40 #include <linux/nfs.h>
41 #define nfsstat nfs_stat
44 #include "pseudoflavors.h"
48 #include "mount_constants.h"
49 #include "nfs4_mount.h"
50 #include "nfs_mount.h"
54 #if defined(VAR_LOCK_DIR)
55 #define DEFAULT_DIR VAR_LOCK_DIR
57 #define DEFAULT_DIR "/var/lock/subsys"
60 extern char *progname;
64 char *IDMAPLCK = DEFAULT_DIR "/rpcidmapd";
65 #define idmapd_check() do { \
66 if (access(IDMAPLCK, F_OK)) { \
67 printf(_("Warning: rpc.idmapd appears not to be running.\n" \
68 " All uids will be mapped to the nobody uid.\n")); \
72 char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
73 #define gssd_check() do { \
74 if (access(GSSDLCK, F_OK)) { \
75 printf(_("Warning: rpc.gssd appears not to be running.\n")); \
83 #define MAX_USER_FLAVOUR 16
85 static int parse_sec(char *sec, int *pseudoflavour)
87 int i, num_flavour = 0;
89 for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
90 if (num_flavour >= MAX_USER_FLAVOUR) {
91 nfs_error(_("%s: maximum number of security flavors "
92 "exceeded"), progname);
95 for (i = 0; i < flav_map_size; i++) {
96 if (strcmp(sec, flav_map[i].flavour) == 0) {
97 pseudoflavour[num_flavour++] = flav_map[i].fnum;
101 if (i == flav_map_size) {
102 nfs_error(_("%s: unknown security type %s\n"),
108 nfs_error(_("%s: no security flavors passed to sec= option"),
113 static int parse_devname(char *hostdir, char **hostname, char **dirname)
117 if (!(s = strchr(hostdir, ':'))) {
118 nfs_error(_("%s: directory to mount not in host:dir format"),
125 /* Ignore all but first hostname in replicated mounts
126 until they can be fully supported. (mack@sgi.com) */
127 if ((s = strchr(hostdir, ','))) {
129 nfs_error(_("%s: warning: multiple hostnames not supported"),
135 static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
138 addr->sin_family = AF_INET;
140 if (inet_aton(hostname, &addr->sin_addr))
142 if ((hp = gethostbyname(hostname)) == NULL) {
143 nfs_error(_("%s: can't get address for %s\n"),
147 if (hp->h_length > sizeof(struct in_addr)) {
148 nfs_error(_("%s: got bad hp->h_length"), progname);
149 hp->h_length = sizeof(struct in_addr);
151 memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
155 static int get_my_ipv4addr(char *ip_addr, int len)
158 struct sockaddr_in myaddr;
160 if (gethostname(myname, sizeof(myname))) {
161 nfs_error(_("%s: can't determine client address\n"),
165 if (fill_ipv4_sockaddr(myname, &myaddr))
167 snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
168 ip_addr[len-1] = '\0';
172 int nfs4mount(const char *spec, const char *node, int flags,
173 char **extra_opts, int fake, int running_bg)
175 static struct nfs4_mount_data data;
176 static char hostdir[1024];
177 static char ip_addr[16] = "127.0.0.1";
178 static struct sockaddr_in server_addr, client_addr;
179 static int pseudoflavour[MAX_USER_FLAVOUR];
181 int ip_addr_in_opts = 0;
183 char *hostname, *dirname, *old_opts;
189 int nocto, noac, unshared;
191 int retval = EX_FAIL;
194 if (strlen(spec) >= sizeof(hostdir)) {
195 nfs_error(_("%s: excessively long host:dir argument\n"),
199 strcpy(hostdir, spec);
200 if (parse_devname(hostdir, &hostname, &dirname))
203 if (fill_ipv4_sockaddr(hostname, &server_addr))
205 if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
208 /* add IP address to mtab options for use when unmounting */
209 s = inet_ntoa(server_addr.sin_addr);
210 old_opts = *extra_opts;
213 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
214 nfs_error(_("%s: excessively long option argument\n"),
218 snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
219 old_opts, *old_opts ? "," : "", s);
220 *extra_opts = xstrdup(new_opts);
222 /* Set default options.
223 * rsize/wsize and timeo are left 0 in order to
224 * let the kernel decide.
226 memset(&data, 0, sizeof(data));
232 data.proto = IPPROTO_TCP;
236 intr = NFS4_MOUNT_INTR;
243 * NFSv4 specifies that the default port should be 2049
245 server_addr.sin_port = htons(NFS_PORT);
249 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
250 if ((opteq = strchr(opt, '='))) {
251 val = atoi(opteq + 1);
253 if (!strcmp(opt, "rsize"))
255 else if (!strcmp(opt, "wsize"))
257 else if (!strcmp(opt, "timeo"))
259 else if (!strcmp(opt, "retrans"))
261 else if (!strcmp(opt, "acregmin"))
263 else if (!strcmp(opt, "acregmax"))
265 else if (!strcmp(opt, "acdirmin"))
267 else if (!strcmp(opt, "acdirmax"))
269 else if (!strcmp(opt, "actimeo")) {
275 else if (!strcmp(opt, "retry"))
277 else if (!strcmp(opt, "port"))
278 server_addr.sin_port = htons(val);
279 else if (!strcmp(opt, "proto")) {
280 if (!strncmp(opteq+1, "tcp", 3))
281 data.proto = IPPROTO_TCP;
282 else if (!strncmp(opteq+1, "udp", 3))
283 data.proto = IPPROTO_UDP;
285 printf(_("Warning: Unrecognized proto= option.\n"));
286 } else if (!strcmp(opt, "clientaddr")) {
287 if (strlen(opteq+1) >= sizeof(ip_addr))
288 printf(_("Invalid client address %s"),
290 strncpy(ip_addr,opteq+1, sizeof(ip_addr));
291 ip_addr[sizeof(ip_addr)-1] = '\0';
293 } else if (!strcmp(opt, "sec")) {
294 num_flavour = parse_sec(opteq+1, pseudoflavour);
297 } else if (!strcmp(opt, "addr") || sloppy) {
300 printf(_("unknown nfs mount parameter: "
301 "%s=%d\n"), opt, val);
306 if (!strncmp(opt, "no", 2)) {
310 if (!strcmp(opt, "bg"))
312 else if (!strcmp(opt, "fg"))
314 else if (!strcmp(opt, "soft"))
316 else if (!strcmp(opt, "hard"))
318 else if (!strcmp(opt, "intr"))
320 else if (!strcmp(opt, "cto"))
322 else if (!strcmp(opt, "ac"))
324 else if (!strcmp(opt, "sharecache"))
327 printf(_("unknown nfs mount option: %s%s\n"),
328 val ? "" : "no", opt);
334 /* if retry is still -1, then it wasn't set via an option */
337 retry = 10000; /* 10000 mins == ~1 week */
339 retry = 2; /* 2 min default on fg mounts */
342 data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
343 | (intr ? NFS4_MOUNT_INTR : 0)
344 | (nocto ? NFS4_MOUNT_NOCTO : 0)
345 | (noac ? NFS4_MOUNT_NOAC : 0)
346 | (unshared ? NFS4_MOUNT_UNSHARED : 0);
349 * Give a warning if the rpc.idmapd daemon is not running
352 /* We shouldn't have these checks as nothing in this package
353 * creates the files that are checked
357 if (num_flavour == 0)
358 pseudoflavour[num_flavour++] = AUTH_UNIX;
361 * ditto with rpc.gssd daemon
366 data.auth_flavourlen = num_flavour;
367 data.auth_flavours = pseudoflavour;
369 data.client_addr.data = ip_addr;
370 data.client_addr.len = strlen(ip_addr);
372 data.mnt_path.data = dirname;
373 data.mnt_path.len = strlen(dirname);
375 data.hostname.data = hostname;
376 data.hostname.len = strlen(hostname);
377 data.host_addr = (struct sockaddr *)&server_addr;
378 data.host_addrlen = sizeof(server_addr);
380 #ifdef NFS_MOUNT_DEBUG
381 printf(_("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n"),
382 data.rsize, data.wsize, data.timeo, data.retrans);
383 printf(_("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n"),
384 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
385 printf(_("port = %d, bg = %d, retry = %d, flags = %.8x\n"),
386 ntohs(server_addr.sin_port), bg, retry, data.flags);
387 printf(_("soft = %d, intr = %d, nocto = %d, noac = %d, "
388 "nosharecache = %d\n"),
389 (data.flags & NFS4_MOUNT_SOFT) != 0,
390 (data.flags & NFS4_MOUNT_INTR) != 0,
391 (data.flags & NFS4_MOUNT_NOCTO) != 0,
392 (data.flags & NFS4_MOUNT_NOAC) != 0,
393 (data.flags & NFS4_MOUNT_UNSHARED) != 0);
395 if (num_flavour > 0) {
399 for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
400 for (i = 0; i < flav_map_size; i++) {
401 if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
402 printf("%s", flav_map[i].flavour);
406 printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
409 printf(_("proto = %s\n"), (data.proto == IPPROTO_TCP) ? _("tcp") : _("udp"));
412 timeout = time(NULL) + 60 * retry;
413 data.version = NFS4_MOUNT_VERSION;
416 printf(_("%s: pinging: prog %d vers %d prot %s port %d\n"),
417 progname, NFS_PROGRAM, 4,
418 data.proto == IPPROTO_UDP ? "udp" : "tcp",
419 ntohs(server_addr.sin_port));
421 client_addr.sin_family = 0;
422 client_addr.sin_addr.s_addr = 0;
423 clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto, &client_addr);
424 if (rpc_createerr.cf_stat == RPC_SUCCESS) {
425 if (!ip_addr_in_opts &&
426 client_addr.sin_family != 0 &&
427 client_addr.sin_addr.s_addr != 0) {
428 snprintf(ip_addr, sizeof(ip_addr), "%s",
429 inet_ntoa(client_addr.sin_addr));
430 data.client_addr.len = strlen(ip_addr);
435 switch(rpc_createerr.cf_stat){
438 case RPC_SYSTEMERROR:
439 if (errno == ETIMEDOUT)
442 rpc_mount_errors(hostname, 0, bg);
446 if (bg && !running_bg) {
454 rpc_mount_errors(hostname, 0, bg);
457 rpc_mount_errors(hostname, 1, bg);
462 if (mount(spec, node, "nfs4",
463 flags & ~(MS_USER|MS_USERS), &data)) {
464 mount_error(spec, node, errno);