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.
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
32 #ifdef HAVE_RPCSVC_NFS_PROT_H
33 #include <rpcsvc/nfs_prot.h>
35 #include <linux/nfs.h>
36 #define nfsstat nfs_stat
43 #include "nfs4_mount.h"
44 #include "nfs_mount.h"
46 #if defined(VAR_LOCK_DIR)
47 #define DEFAULT_DIR VAR_LOCK_DIR
49 #define DEFAULT_DIR "/var/lock/subsys"
54 char *IDMAPLCK = DEFAULT_DIR "/rpcidmapd";
55 #define idmapd_check() do { \
56 if (access(IDMAPLCK, F_OK)) { \
57 printf(_("Warning: rpc.idmapd appears not to be running.\n" \
58 " All uids will be mapped to the nobody uid.\n")); \
62 char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
63 #define gssd_check() do { \
64 if (access(GSSDLCK, F_OK)) { \
65 printf(_("Warning: rpc.gssd appears not to be running.\n")); \
77 { "krb5", RPC_AUTH_GSS_KRB5 },
78 { "krb5i", RPC_AUTH_GSS_KRB5I },
79 { "krb5p", RPC_AUTH_GSS_KRB5P },
80 { "lipkey", RPC_AUTH_GSS_LKEY },
81 { "lipkey-i", RPC_AUTH_GSS_LKEYI },
82 { "lipkey-p", RPC_AUTH_GSS_LKEYP },
83 { "spkm3", RPC_AUTH_GSS_SPKM },
84 { "spkm3i", RPC_AUTH_GSS_SPKMI },
85 { "spkm3p", RPC_AUTH_GSS_SPKMP },
86 { "unix", AUTH_UNIX },
88 { "null", AUTH_NULL },
89 { "none", AUTH_NONE },
92 #define FMAPSIZE (sizeof(flav_map)/sizeof(flav_map[0]))
93 #define MAX_USER_FLAVOUR 16
95 static int parse_sec(char *sec, int *pseudoflavour)
97 int i, num_flavour = 0;
99 for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
100 if (num_flavour >= MAX_USER_FLAVOUR) {
102 _("mount: maximum number of security flavors "
106 for (i = 0; i < FMAPSIZE; i++) {
107 if (strcmp(sec, flav_map[i].flavour) == 0) {
108 pseudoflavour[num_flavour++] = flav_map[i].fnum;
114 _("mount: unknown security type %s\n"), sec);
120 _("mount: no security flavors passed to sec= option\n"));
124 static int parse_devname(char *hostdir, char **hostname, char **dirname)
128 if (!(s = strchr(hostdir, ':'))) {
131 "directory to mount not in host:dir format\n"));
137 /* Ignore all but first hostname in replicated mounts
138 until they can be fully supported. (mack@sgi.com) */
139 if ((s = strchr(hostdir, ','))) {
143 "multiple hostnames not supported\n"));
148 static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
151 addr->sin_family = AF_INET;
153 if (inet_aton(hostname, &addr->sin_addr))
155 if ((hp = gethostbyname(hostname)) == NULL) {
156 fprintf(stderr, _("mount: can't get address for %s\n"),
160 if (hp->h_length > sizeof(struct in_addr)) {
162 _("mount: got bad hp->h_length\n"));
163 hp->h_length = sizeof(struct in_addr);
165 memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
169 static int get_my_ipv4addr(char *ip_addr, int len)
172 struct sockaddr_in myaddr;
174 if (gethostname(myname, sizeof(myname))) {
175 fprintf(stderr, _("mount: can't determine client address\n"));
178 if (fill_ipv4_sockaddr(myname, &myaddr))
180 snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
181 ip_addr[len-1] = '\0';
185 int nfs4mount(const char *spec, const char *node, int *flags,
186 char **extra_opts, char **mount_opts,
189 static struct nfs4_mount_data data;
190 static char hostdir[1024];
191 static char ip_addr[16] = "127.0.0.1";
192 static struct sockaddr_in server_addr;
193 static int pseudoflavour[MAX_USER_FLAVOUR];
196 char *hostname, *dirname, *old_opts;
208 if (strlen(spec) >= sizeof(hostdir)) {
209 fprintf(stderr, _("mount: "
210 "excessively long host:dir argument\n"));
213 strcpy(hostdir, spec);
214 if (parse_devname(hostdir, &hostname, &dirname))
217 if (fill_ipv4_sockaddr(hostname, &server_addr))
219 if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
222 /* add IP address to mtab options for use when unmounting */
223 s = inet_ntoa(server_addr.sin_addr);
224 old_opts = *extra_opts;
227 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
228 fprintf(stderr, _("mount: "
229 "excessively long option argument\n"));
232 snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
233 old_opts, *old_opts ? "," : "", s);
234 *extra_opts = xstrdup(new_opts);
236 /* Set default options.
237 * rsize/wsize and timeo are left 0 in order to
238 * let the kernel decide.
240 memset(&data, 0, sizeof(data));
246 data.proto = IPPROTO_TCP;
250 intr = NFS4_MOUNT_INTR;
253 retry = 10000; /* 10000 minutes ~ 1 week */
256 * NFSv4 specifies that the default port should be 2049
258 server_addr.sin_port = htons(NFS_PORT);
262 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
263 if ((opteq = strchr(opt, '='))) {
264 val = atoi(opteq + 1);
266 if (!strcmp(opt, "rsize"))
268 else if (!strcmp(opt, "wsize"))
270 else if (!strcmp(opt, "timeo"))
272 else if (!strcmp(opt, "retrans"))
274 else if (!strcmp(opt, "acregmin"))
276 else if (!strcmp(opt, "acregmax"))
278 else if (!strcmp(opt, "acdirmin"))
280 else if (!strcmp(opt, "acdirmax"))
282 else if (!strcmp(opt, "actimeo")) {
288 else if (!strcmp(opt, "retry"))
290 else if (!strcmp(opt, "port"))
291 server_addr.sin_port = htons(val);
292 else if (!strcmp(opt, "proto")) {
293 if (!strncmp(opteq+1, "tcp", 3))
294 data.proto = IPPROTO_TCP;
295 else if (!strncmp(opteq+1, "udp", 3))
296 data.proto = IPPROTO_UDP;
298 printf(_("Warning: Unrecognized proto= option.\n"));
299 } else if (!strcmp(opt, "clientaddr")) {
300 if (strlen(opteq+1) >= sizeof(ip_addr))
301 printf(_("Invalid client address %s"),
303 strncpy(ip_addr,opteq+1, sizeof(ip_addr));
304 ip_addr[sizeof(ip_addr)-1] = '\0';
305 } else if (!strcmp(opt, "sec")) {
306 num_flavour = parse_sec(opteq+1, pseudoflavour);
309 } else if (!strcmp(opt, "addr")) {
312 printf(_("unknown nfs mount parameter: "
313 "%s=%d\n"), opt, val);
318 if (!strncmp(opt, "no", 2)) {
322 if (!strcmp(opt, "bg"))
324 else if (!strcmp(opt, "fg"))
326 else if (!strcmp(opt, "soft"))
328 else if (!strcmp(opt, "hard"))
330 else if (!strcmp(opt, "intr"))
332 else if (!strcmp(opt, "cto"))
334 else if (!strcmp(opt, "ac"))
337 printf(_("unknown nfs mount option: "
338 "%s%s\n"), val ? "" : "no", opt);
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);
350 * Give a warning if the rpc.idmapd daemon is not running
354 if (num_flavour == 0)
355 pseudoflavour[num_flavour++] = AUTH_UNIX;
358 * ditto with rpc.gssd daemon
362 data.auth_flavourlen = num_flavour;
363 data.auth_flavours = pseudoflavour;
365 data.client_addr.data = ip_addr;
366 data.client_addr.len = strlen(ip_addr);
368 data.mnt_path.data = dirname;
369 data.mnt_path.len = strlen(dirname);
371 data.hostname.data = hostname;
372 data.hostname.len = strlen(hostname);
373 data.host_addr = (struct sockaddr *)&server_addr;
374 data.host_addrlen = sizeof(server_addr);
376 #ifdef NFS_MOUNT_DEBUG
377 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
378 data.rsize, data.wsize, data.timeo, data.retrans);
379 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
380 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
381 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
382 ntohs(server_addr.sin_port), bg, retry, data.flags);
383 printf("soft = %d, intr = %d, nocto = %d, noac = %d\n",
384 (data.flags & NFS4_MOUNT_SOFT) != 0,
385 (data.flags & NFS4_MOUNT_INTR) != 0,
386 (data.flags & NFS4_MOUNT_NOCTO) != 0,
387 (data.flags & NFS4_MOUNT_NOAC) != 0);
389 if (num_flavour > 0) {
393 for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
394 for (i = 0; i < FMAPSIZE; i++) {
395 if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
396 printf("%s", flav_map[i].flavour);
400 printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
403 printf("proto = %s\n", (data.proto == IPPROTO_TCP) ? "tcp" : "udp");
406 timeout = time(NULL) + 60 * retry;
407 data.version = NFS4_MOUNT_VERSION;
411 "mount: pinging: prog %d vers %d prot %s port %d\n",
412 NFS_PROGRAM, 4, data.proto == IPPROTO_UDP ? "udp" : "tcp",
413 ntohs(server_addr.sin_port));
415 clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto);
416 if (rpc_createerr.cf_stat == RPC_SUCCESS)
419 switch(rpc_createerr.cf_stat){
422 case RPC_SYSTEMERROR:
423 if (errno == ETIMEDOUT)
426 mount_errors(hostname, 0, bg);
431 mount_errors(hostname, 0, bg);
434 mount_errors(hostname, 1, bg);
438 *mount_opts = (char *) &data;