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, client_addr;
193
static int pseudoflavour[MAX_USER_FLAVOUR];
195
int ip_addr_in_opts = 0;
197
char *hostname, *dirname, *old_opts;
209
if (strlen(spec) >= sizeof(hostdir)) {
210
fprintf(stderr, _("mount: "
211
"excessively long host:dir argument\n"));
214
strcpy(hostdir, spec);
215
if (parse_devname(hostdir, &hostname, &dirname))
218
if (fill_ipv4_sockaddr(hostname, &server_addr))
220
if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
223
/* add IP address to mtab options for use when unmounting */
224
s = inet_ntoa(server_addr.sin_addr);
225
old_opts = *extra_opts;
228
if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
229
fprintf(stderr, _("mount: "
230
"excessively long option argument\n"));
233
snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
234
old_opts, *old_opts ? "," : "", s);
235
*extra_opts = xstrdup(new_opts);
237
/* Set default options.
238
* rsize/wsize and timeo are left 0 in order to
239
* let the kernel decide.
241
memset(&data, 0, sizeof(data));
247
data.proto = IPPROTO_TCP;
251
intr = NFS4_MOUNT_INTR;
254
retry = 10000; /* 10000 minutes ~ 1 week */
257
* NFSv4 specifies that the default port should be 2049
259
server_addr.sin_port = htons(NFS_PORT);
263
for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
264
if ((opteq = strchr(opt, '='))) {
265
val = atoi(opteq + 1);
267
if (!strcmp(opt, "rsize"))
269
else if (!strcmp(opt, "wsize"))
271
else if (!strcmp(opt, "timeo"))
273
else if (!strcmp(opt, "retrans"))
275
else if (!strcmp(opt, "acregmin"))
277
else if (!strcmp(opt, "acregmax"))
279
else if (!strcmp(opt, "acdirmin"))
281
else if (!strcmp(opt, "acdirmax"))
283
else if (!strcmp(opt, "actimeo")) {
289
else if (!strcmp(opt, "retry"))
291
else if (!strcmp(opt, "port"))
292
server_addr.sin_port = htons(val);
293
else if (!strcmp(opt, "proto")) {
294
if (!strncmp(opteq+1, "tcp", 3))
295
data.proto = IPPROTO_TCP;
296
else if (!strncmp(opteq+1, "udp", 3))
297
data.proto = IPPROTO_UDP;
299
printf(_("Warning: Unrecognized proto= option.\n"));
300
} else if (!strcmp(opt, "clientaddr")) {
301
if (strlen(opteq+1) >= sizeof(ip_addr))
302
printf(_("Invalid client address %s"),
304
strncpy(ip_addr,opteq+1, sizeof(ip_addr));
305
ip_addr[sizeof(ip_addr)-1] = '\0';
307
} else if (!strcmp(opt, "sec")) {
308
num_flavour = parse_sec(opteq+1, pseudoflavour);
311
} else if (!strcmp(opt, "addr")) {
314
printf(_("unknown nfs mount parameter: "
315
"%s=%d\n"), opt, val);
320
if (!strncmp(opt, "no", 2)) {
324
if (!strcmp(opt, "bg"))
326
else if (!strcmp(opt, "fg"))
328
else if (!strcmp(opt, "soft"))
330
else if (!strcmp(opt, "hard"))
332
else if (!strcmp(opt, "intr"))
334
else if (!strcmp(opt, "cto"))
336
else if (!strcmp(opt, "ac"))
339
printf(_("unknown nfs mount option: "
340
"%s%s\n"), val ? "" : "no", opt);
346
data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
347
| (intr ? NFS4_MOUNT_INTR : 0)
348
| (nocto ? NFS4_MOUNT_NOCTO : 0)
349
| (noac ? NFS4_MOUNT_NOAC : 0);
352
* Give a warning if the rpc.idmapd daemon is not running
356
if (num_flavour == 0)
357
pseudoflavour[num_flavour++] = AUTH_UNIX;
360
* ditto with rpc.gssd daemon
364
data.auth_flavourlen = num_flavour;
365
data.auth_flavours = pseudoflavour;
367
data.client_addr.data = ip_addr;
368
data.client_addr.len = strlen(ip_addr);
370
data.mnt_path.data = dirname;
371
data.mnt_path.len = strlen(dirname);
373
data.hostname.data = hostname;
374
data.hostname.len = strlen(hostname);
375
data.host_addr = (struct sockaddr *)&server_addr;
376
data.host_addrlen = sizeof(server_addr);
378
#ifdef NFS_MOUNT_DEBUG
379
printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
380
data.rsize, data.wsize, data.timeo, data.retrans);
381
printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
382
data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
383
printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
384
ntohs(server_addr.sin_port), bg, retry, data.flags);
385
printf("soft = %d, intr = %d, nocto = %d, noac = %d\n",
386
(data.flags & NFS4_MOUNT_SOFT) != 0,
387
(data.flags & NFS4_MOUNT_INTR) != 0,
388
(data.flags & NFS4_MOUNT_NOCTO) != 0,
389
(data.flags & NFS4_MOUNT_NOAC) != 0);
391
if (num_flavour > 0) {
395
for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
396
for (i = 0; i < FMAPSIZE; i++) {
397
if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
398
printf("%s", flav_map[i].flavour);
402
printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
405
printf("proto = %s\n", (data.proto == IPPROTO_TCP) ? "tcp" : "udp");
408
timeout = time(NULL) + 60 * retry;
409
data.version = NFS4_MOUNT_VERSION;
413
"mount: pinging: prog %d vers %d prot %s port %d\n",
414
NFS_PROGRAM, 4, data.proto == IPPROTO_UDP ? "udp" : "tcp",
415
ntohs(server_addr.sin_port));
417
client_addr.sin_family = 0;
418
client_addr.sin_addr.s_addr = 0;
419
clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto, &client_addr);
420
if (rpc_createerr.cf_stat == RPC_SUCCESS) {
421
if (!ip_addr_in_opts &&
422
client_addr.sin_family != 0 &&
423
client_addr.sin_addr.s_addr != 0) {
424
snprintf(ip_addr, sizeof(ip_addr), "%s",
425
inet_ntoa(client_addr.sin_addr));
426
data.client_addr.len = strlen(ip_addr);
431
switch(rpc_createerr.cf_stat){
434
case RPC_SYSTEMERROR:
435
if (errno == ETIMEDOUT)
438
mount_errors(hostname, 0, bg);
443
mount_errors(hostname, 0, bg);
446
mount_errors(hostname, 1, bg);
450
*mount_opts = (char *) &data;