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>
38 #ifdef HAVE_RPCSVC_NFS_PROT_H
39 #include <rpcsvc/nfs_prot.h>
41 #include <linux/nfs.h>
42 #define nfsstat nfs_stat
45 #include "pseudoflavors.h"
50 #include "mount_constants.h"
51 #include "nfs4_mount.h"
52 #include "nfs_mount.h"
56 #if defined(VAR_LOCK_DIR)
57 #define DEFAULT_DIR VAR_LOCK_DIR
59 #define DEFAULT_DIR "/var/lock/subsys"
62 extern char *progname;
66 char *IDMAPLCK = DEFAULT_DIR "/rpcidmapd";
67 #define idmapd_check() do { \
68 if (access(IDMAPLCK, F_OK)) { \
69 printf(_("Warning: rpc.idmapd appears not to be running.\n" \
70 " All uids will be mapped to the nobody uid.\n")); \
74 char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
75 #define gssd_check() do { \
76 if (access(GSSDLCK, F_OK)) { \
77 printf(_("Warning: rpc.gssd appears not to be running.\n")); \
85 #define MAX_USER_FLAVOUR 16
87 static int parse_sec(char *sec, int *pseudoflavour)
89 int i, num_flavour = 0;
91 for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
92 if (num_flavour >= MAX_USER_FLAVOUR) {
93 nfs_error(_("%s: maximum number of security flavors "
94 "exceeded"), progname);
97 for (i = 0; i < flav_map_size; i++) {
98 if (strcmp(sec, flav_map[i].flavour) == 0) {
99 pseudoflavour[num_flavour++] = flav_map[i].fnum;
103 if (i == flav_map_size) {
104 nfs_error(_("%s: unknown security type %s\n"),
110 nfs_error(_("%s: no security flavors passed to sec= option"),
115 static int parse_devname(char *hostdir, char **hostname, char **dirname)
119 if (!(s = strchr(hostdir, ':'))) {
120 nfs_error(_("%s: directory to mount not in host:dir format"),
127 /* Ignore all but first hostname in replicated mounts
128 until they can be fully supported. (mack@sgi.com) */
129 if ((s = strchr(hostdir, ','))) {
131 nfs_error(_("%s: warning: multiple hostnames not supported"),
137 static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
140 addr->sin_family = AF_INET;
142 if (inet_aton(hostname, &addr->sin_addr))
144 if ((hp = gethostbyname(hostname)) == NULL) {
145 nfs_error(_("%s: can't get address for %s\n"),
149 if (hp->h_length > sizeof(struct in_addr)) {
150 nfs_error(_("%s: got bad hp->h_length"), progname);
151 hp->h_length = sizeof(struct in_addr);
153 memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
157 static int get_my_ipv4addr(char *ip_addr, int len)
160 struct sockaddr_in myaddr;
162 if (gethostname(myname, sizeof(myname))) {
163 nfs_error(_("%s: can't determine client address\n"),
167 if (fill_ipv4_sockaddr(myname, &myaddr))
169 snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
170 ip_addr[len-1] = '\0';
174 int nfs4mount(const char *spec, const char *node, int flags,
175 char **extra_opts, int fake, int running_bg)
177 static struct nfs4_mount_data data;
178 static char hostdir[1024];
179 static char ip_addr[16] = "127.0.0.1";
180 static struct sockaddr_in server_addr, client_addr;
181 static int pseudoflavour[MAX_USER_FLAVOUR];
183 int ip_addr_in_opts = 0;
185 char *hostname, *dirname, *old_opts;
191 int nocto, noac, unshared;
193 int retval = EX_FAIL;
196 if (strlen(spec) >= sizeof(hostdir)) {
197 nfs_error(_("%s: excessively long host:dir argument\n"),
201 strcpy(hostdir, spec);
202 if (parse_devname(hostdir, &hostname, &dirname))
205 if (fill_ipv4_sockaddr(hostname, &server_addr))
207 if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
210 /* add IP address to mtab options for use when unmounting */
211 s = inet_ntoa(server_addr.sin_addr);
212 old_opts = *extra_opts;
215 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
216 nfs_error(_("%s: excessively long option argument\n"),
220 snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
221 old_opts, *old_opts ? "," : "", s);
222 *extra_opts = xstrdup(new_opts);
224 /* Set default options.
225 * rsize/wsize and timeo are left 0 in order to
226 * let the kernel decide.
228 memset(&data, 0, sizeof(data));
234 data.proto = IPPROTO_TCP;
238 intr = NFS4_MOUNT_INTR;
245 * NFSv4 specifies that the default port should be 2049
247 server_addr.sin_port = htons(NFS_PORT);
251 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
252 if ((opteq = strchr(opt, '='))) {
253 val = atoi(opteq + 1);
255 if (!strcmp(opt, "rsize"))
257 else if (!strcmp(opt, "wsize"))
259 else if (!strcmp(opt, "timeo"))
261 else if (!strcmp(opt, "retrans"))
263 else if (!strcmp(opt, "acregmin"))
265 else if (!strcmp(opt, "acregmax"))
267 else if (!strcmp(opt, "acdirmin"))
269 else if (!strcmp(opt, "acdirmax"))
271 else if (!strcmp(opt, "actimeo")) {
277 else if (!strcmp(opt, "retry"))
279 else if (!strcmp(opt, "port"))
280 server_addr.sin_port = htons(val);
281 else if (!strcmp(opt, "proto")) {
282 if (!strncmp(opteq+1, "tcp", 3))
283 data.proto = IPPROTO_TCP;
284 else if (!strncmp(opteq+1, "udp", 3))
285 data.proto = IPPROTO_UDP;
287 printf(_("Warning: Unrecognized proto= option.\n"));
288 } else if (!strcmp(opt, "clientaddr")) {
289 if (strlen(opteq+1) >= sizeof(ip_addr))
290 printf(_("Invalid client address %s"),
292 strncpy(ip_addr,opteq+1, sizeof(ip_addr));
293 ip_addr[sizeof(ip_addr)-1] = '\0';
295 } else if (!strcmp(opt, "sec")) {
296 num_flavour = parse_sec(opteq+1, pseudoflavour);
299 } else if (!strcmp(opt, "addr") || sloppy) {
302 printf(_("unknown nfs mount parameter: "
303 "%s=%d\n"), opt, val);
308 if (!strncmp(opt, "no", 2)) {
312 if (!strcmp(opt, "bg"))
314 else if (!strcmp(opt, "fg"))
316 else if (!strcmp(opt, "soft"))
318 else if (!strcmp(opt, "hard"))
320 else if (!strcmp(opt, "intr"))
322 else if (!strcmp(opt, "cto"))
324 else if (!strcmp(opt, "ac"))
326 else if (!strcmp(opt, "sharecache"))
329 printf(_("unknown nfs mount option: %s%s\n"),
330 val ? "" : "no", opt);
336 /* if retry is still -1, then it wasn't set via an option */
339 retry = 10000; /* 10000 mins == ~1 week */
341 retry = 2; /* 2 min default on fg mounts */
344 data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
345 | (intr ? NFS4_MOUNT_INTR : 0)
346 | (nocto ? NFS4_MOUNT_NOCTO : 0)
347 | (noac ? NFS4_MOUNT_NOAC : 0)
348 | (unshared ? NFS4_MOUNT_UNSHARED : 0);
351 * Give a warning if the rpc.idmapd daemon is not running
354 /* We shouldn't have these checks as nothing in this package
355 * creates the files that are checked
359 if (num_flavour == 0)
360 pseudoflavour[num_flavour++] = AUTH_UNIX;
363 * ditto with rpc.gssd daemon
368 data.auth_flavourlen = num_flavour;
369 data.auth_flavours = pseudoflavour;
371 data.client_addr.data = ip_addr;
372 data.client_addr.len = strlen(ip_addr);
374 data.mnt_path.data = dirname;
375 data.mnt_path.len = strlen(dirname);
377 data.hostname.data = hostname;
378 data.hostname.len = strlen(hostname);
379 data.host_addr = (struct sockaddr *)&server_addr;
380 data.host_addrlen = sizeof(server_addr);
382 #ifdef NFS_MOUNT_DEBUG
383 printf(_("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n"),
384 data.rsize, data.wsize, data.timeo, data.retrans);
385 printf(_("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n"),
386 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
387 printf(_("port = %d, bg = %d, retry = %d, flags = %.8x\n"),
388 ntohs(server_addr.sin_port), bg, retry, data.flags);
389 printf(_("soft = %d, intr = %d, nocto = %d, noac = %d, "
390 "nosharecache = %d\n"),
391 (data.flags & NFS4_MOUNT_SOFT) != 0,
392 (data.flags & NFS4_MOUNT_INTR) != 0,
393 (data.flags & NFS4_MOUNT_NOCTO) != 0,
394 (data.flags & NFS4_MOUNT_NOAC) != 0,
395 (data.flags & NFS4_MOUNT_UNSHARED) != 0);
397 if (num_flavour > 0) {
401 for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
402 for (i = 0; i < flav_map_size; i++) {
403 if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
404 printf("%s", flav_map[i].flavour);
408 printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
411 printf(_("proto = %s\n"), (data.proto == IPPROTO_TCP) ? _("tcp") : _("udp"));
414 timeout = time(NULL) + 60 * retry;
415 data.version = NFS4_MOUNT_VERSION;
418 printf(_("%s: pinging: prog %d vers %d prot %s port %d\n"),
419 progname, NFS_PROGRAM, 4,
420 data.proto == IPPROTO_UDP ? "udp" : "tcp",
421 ntohs(server_addr.sin_port));
423 client_addr.sin_family = 0;
424 client_addr.sin_addr.s_addr = 0;
425 clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto, &client_addr);
426 if (rpc_createerr.cf_stat == RPC_SUCCESS) {
427 if (!ip_addr_in_opts &&
428 client_addr.sin_family != 0 &&
429 client_addr.sin_addr.s_addr != 0) {
430 snprintf(ip_addr, sizeof(ip_addr), "%s",
431 inet_ntoa(client_addr.sin_addr));
432 data.client_addr.len = strlen(ip_addr);
437 switch(rpc_createerr.cf_stat){
440 case RPC_SYSTEMERROR:
441 if (errno == ETIMEDOUT)
444 rpc_mount_errors(hostname, 0, bg);
448 if (bg && !running_bg) {
456 rpc_mount_errors(hostname, 0, bg);
459 rpc_mount_errors(hostname, 1, bg);
464 if (mount(spec, node, "nfs4",
465 flags & ~(MS_USER|MS_USERS), &data)) {
466 mount_error(spec, node, errno);