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"
55 char *IDMAPLCK = DEFAULT_DIR "/rpcidmapd";
56 #define idmapd_check() do { \
57 if (access(IDMAPLCK, F_OK)) { \
58 printf(_("Warning: rpc.idmapd appears not to be running.\n" \
59 " All uids will be mapped to the nobody uid.\n")); \
63 char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
64 #define gssd_check() do { \
65 if (access(GSSDLCK, F_OK)) { \
66 printf(_("Warning: rpc.gssd appears not to be running.\n")); \
78 { "krb5", RPC_AUTH_GSS_KRB5 },
79 { "krb5i", RPC_AUTH_GSS_KRB5I },
80 { "krb5p", RPC_AUTH_GSS_KRB5P },
81 { "lipkey", RPC_AUTH_GSS_LKEY },
82 { "lipkey-i", RPC_AUTH_GSS_LKEYI },
83 { "lipkey-p", RPC_AUTH_GSS_LKEYP },
84 { "spkm3", RPC_AUTH_GSS_SPKM },
85 { "spkm3i", RPC_AUTH_GSS_SPKMI },
86 { "spkm3p", RPC_AUTH_GSS_SPKMP },
87 { "unix", AUTH_UNIX },
89 { "null", AUTH_NULL },
90 { "none", AUTH_NONE },
93 #define FMAPSIZE (sizeof(flav_map)/sizeof(flav_map[0]))
94 #define MAX_USER_FLAVOUR 16
96 static int parse_sec(char *sec, int *pseudoflavour)
98 int i, num_flavour = 0;
100 for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
101 if (num_flavour >= MAX_USER_FLAVOUR) {
103 _("mount: maximum number of security flavors "
107 for (i = 0; i < FMAPSIZE; i++) {
108 if (strcmp(sec, flav_map[i].flavour) == 0) {
109 pseudoflavour[num_flavour++] = flav_map[i].fnum;
115 _("mount: unknown security type %s\n"), sec);
121 _("mount: no security flavors passed to sec= option\n"));
125 static int parse_devname(char *hostdir, char **hostname, char **dirname)
129 if (!(s = strchr(hostdir, ':'))) {
132 "directory to mount not in host:dir format\n"));
138 /* Ignore all but first hostname in replicated mounts
139 until they can be fully supported. (mack@sgi.com) */
140 if ((s = strchr(hostdir, ','))) {
144 "multiple hostnames not supported\n"));
149 static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
152 addr->sin_family = AF_INET;
154 if (inet_aton(hostname, &addr->sin_addr))
156 if ((hp = gethostbyname(hostname)) == NULL) {
157 fprintf(stderr, _("mount: can't get address for %s\n"),
161 if (hp->h_length > sizeof(struct in_addr)) {
163 _("mount: got bad hp->h_length\n"));
164 hp->h_length = sizeof(struct in_addr);
166 memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
170 static int get_my_ipv4addr(char *ip_addr, int len)
173 struct sockaddr_in myaddr;
175 if (gethostname(myname, sizeof(myname))) {
176 fprintf(stderr, _("mount: can't determine client address\n"));
179 if (fill_ipv4_sockaddr(myname, &myaddr))
181 snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
182 ip_addr[len-1] = '\0';
186 int nfs4mount(const char *spec, const char *node, int *flags,
187 char **extra_opts, char **mount_opts,
190 static struct nfs4_mount_data data;
191 static char hostdir[1024];
192 static char ip_addr[16] = "127.0.0.1";
193 static struct sockaddr_in server_addr, client_addr;
194 static int pseudoflavour[MAX_USER_FLAVOUR];
196 int ip_addr_in_opts = 0;
198 char *hostname, *dirname, *old_opts;
204 int nocto, noac, unshared;
210 if (strlen(spec) >= sizeof(hostdir)) {
211 fprintf(stderr, _("mount: "
212 "excessively long host:dir argument\n"));
215 strcpy(hostdir, spec);
216 if (parse_devname(hostdir, &hostname, &dirname))
219 if (fill_ipv4_sockaddr(hostname, &server_addr))
221 if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
224 /* add IP address to mtab options for use when unmounting */
225 s = inet_ntoa(server_addr.sin_addr);
226 old_opts = *extra_opts;
229 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
230 fprintf(stderr, _("mount: "
231 "excessively long option argument\n"));
234 snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
235 old_opts, *old_opts ? "," : "", s);
236 *extra_opts = xstrdup(new_opts);
238 /* Set default options.
239 * rsize/wsize and timeo are left 0 in order to
240 * let the kernel decide.
242 memset(&data, 0, sizeof(data));
248 data.proto = IPPROTO_TCP;
252 intr = NFS4_MOUNT_INTR;
256 retry = 10000; /* 10000 minutes ~ 1 week */
259 * NFSv4 specifies that the default port should be 2049
261 server_addr.sin_port = htons(NFS_PORT);
265 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
266 if ((opteq = strchr(opt, '='))) {
267 val = atoi(opteq + 1);
269 if (!strcmp(opt, "rsize"))
271 else if (!strcmp(opt, "wsize"))
273 else if (!strcmp(opt, "timeo"))
275 else if (!strcmp(opt, "retrans"))
277 else if (!strcmp(opt, "acregmin"))
279 else if (!strcmp(opt, "acregmax"))
281 else if (!strcmp(opt, "acdirmin"))
283 else if (!strcmp(opt, "acdirmax"))
285 else if (!strcmp(opt, "actimeo")) {
291 else if (!strcmp(opt, "retry"))
293 else if (!strcmp(opt, "port"))
294 server_addr.sin_port = htons(val);
295 else if (!strcmp(opt, "proto")) {
296 if (!strncmp(opteq+1, "tcp", 3))
297 data.proto = IPPROTO_TCP;
298 else if (!strncmp(opteq+1, "udp", 3))
299 data.proto = IPPROTO_UDP;
301 printf(_("Warning: Unrecognized proto= option.\n"));
302 } else if (!strcmp(opt, "clientaddr")) {
303 if (strlen(opteq+1) >= sizeof(ip_addr))
304 printf(_("Invalid client address %s"),
306 strncpy(ip_addr,opteq+1, sizeof(ip_addr));
307 ip_addr[sizeof(ip_addr)-1] = '\0';
309 } else if (!strcmp(opt, "sec")) {
310 num_flavour = parse_sec(opteq+1, pseudoflavour);
313 } else if (!strcmp(opt, "addr") || sloppy) {
316 printf(_("unknown nfs mount parameter: "
317 "%s=%d\n"), opt, val);
322 if (!strncmp(opt, "no", 2)) {
326 if (!strcmp(opt, "bg"))
328 else if (!strcmp(opt, "fg"))
330 else if (!strcmp(opt, "soft"))
332 else if (!strcmp(opt, "hard"))
334 else if (!strcmp(opt, "intr"))
336 else if (!strcmp(opt, "cto"))
338 else if (!strcmp(opt, "ac"))
340 else if (!strcmp(opt, "sharecache"))
343 printf(_("unknown nfs mount option: "
344 "%s%s\n"), val ? "" : "no", opt);
350 data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
351 | (intr ? NFS4_MOUNT_INTR : 0)
352 | (nocto ? NFS4_MOUNT_NOCTO : 0)
353 | (noac ? NFS4_MOUNT_NOAC : 0)
354 | (unshared ? NFS4_MOUNT_UNSHARED : 0);
357 * Give a warning if the rpc.idmapd daemon is not running
360 /* We shouldn't have these checks as nothing in this package
361 * creates the files that are checked
365 if (num_flavour == 0)
366 pseudoflavour[num_flavour++] = AUTH_UNIX;
369 * ditto with rpc.gssd daemon
374 data.auth_flavourlen = num_flavour;
375 data.auth_flavours = pseudoflavour;
377 data.client_addr.data = ip_addr;
378 data.client_addr.len = strlen(ip_addr);
380 data.mnt_path.data = dirname;
381 data.mnt_path.len = strlen(dirname);
383 data.hostname.data = hostname;
384 data.hostname.len = strlen(hostname);
385 data.host_addr = (struct sockaddr *)&server_addr;
386 data.host_addrlen = sizeof(server_addr);
388 #ifdef NFS_MOUNT_DEBUG
389 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
390 data.rsize, data.wsize, data.timeo, data.retrans);
391 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
392 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
393 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
394 ntohs(server_addr.sin_port), bg, retry, data.flags);
395 printf("soft = %d, intr = %d, nocto = %d, noac = %d, "
396 "nosharecache = %d\n",
397 (data.flags & NFS4_MOUNT_SOFT) != 0,
398 (data.flags & NFS4_MOUNT_INTR) != 0,
399 (data.flags & NFS4_MOUNT_NOCTO) != 0,
400 (data.flags & NFS4_MOUNT_NOAC) != 0,
401 (data.flags & NFS4_MOUNT_UNSHARED) != 0);
403 if (num_flavour > 0) {
407 for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
408 for (i = 0; i < FMAPSIZE; i++) {
409 if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
410 printf("%s", flav_map[i].flavour);
414 printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
417 printf("proto = %s\n", (data.proto == IPPROTO_TCP) ? "tcp" : "udp");
420 timeout = time(NULL) + 60 * retry;
421 data.version = NFS4_MOUNT_VERSION;
425 "mount: pinging: prog %d vers %d prot %s port %d\n",
426 NFS_PROGRAM, 4, data.proto == IPPROTO_UDP ? "udp" : "tcp",
427 ntohs(server_addr.sin_port));
429 client_addr.sin_family = 0;
430 client_addr.sin_addr.s_addr = 0;
431 clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto, &client_addr);
432 if (rpc_createerr.cf_stat == RPC_SUCCESS) {
433 if (!ip_addr_in_opts &&
434 client_addr.sin_family != 0 &&
435 client_addr.sin_addr.s_addr != 0) {
436 snprintf(ip_addr, sizeof(ip_addr), "%s",
437 inet_ntoa(client_addr.sin_addr));
438 data.client_addr.len = strlen(ip_addr);
443 switch(rpc_createerr.cf_stat){
446 case RPC_SYSTEMERROR:
447 if (errno == ETIMEDOUT)
450 mount_errors(hostname, 0, bg);
455 mount_errors(hostname, 0, bg);
458 mount_errors(hostname, 1, bg);
462 *mount_opts = (char *) &data;