a few minor cleanups.
[oweals/busybox.git] / util-linux / nfsmount.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * nfsmount.c -- Linux NFS mount
4  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
17  * numbers to be specified on the command line.
18  *
19  * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
20  * Omit the call to connect() for Linux version 1.3.11 or later.
21  *
22  * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
23  * Implemented the "bg", "fg" and "retry" mount options for NFS.
24  *
25  * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
26  * - added Native Language Support
27  * 
28  */
29
30 /*
31  * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
32  */
33
34 #include <unistd.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <netdb.h>
39 #include <rpc/rpc.h>
40 #include <rpc/pmap_prot.h>
41 #include <rpc/pmap_clnt.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <sys/utsname.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #include "nfsmount.h"
50
51 #include <linux/nfs.h>
52 /* we suppose that libc-dev is providing NFSv3 headers (kernel >= 2.2) */
53 #include <linux/nfs_mount.h>
54
55 #define _
56 #define HAVE_inet_aton
57 #define MS_REMOUNT      32                      /* Alter flags of a mounted FS */
58 #define sloppy 0
59 #define EX_FAIL 1
60 #define EX_BG 1
61 #define xstrdup strdup
62 #define xstrndup strndup
63
64
65 static char *nfs_strerror(int stat);
66
67 #define MAKE_VERSION(p,q,r)     (65536*(p) + 256*(q) + (r))
68
69 static int linux_version_code(void)
70 {
71         struct utsname my_utsname;
72         int p, q, r;
73
74         if (uname(&my_utsname) == 0) {
75                 p = atoi(strtok(my_utsname.release, "."));
76                 q = atoi(strtok(NULL, "."));
77                 r = atoi(strtok(NULL, "."));
78                 return MAKE_VERSION(p, q, r);
79         }
80         return 0;
81 }
82
83 /*
84  * nfs_mount_version according to the kernel sources seen at compile time.
85  */
86 static int nfs_mount_version = NFS_MOUNT_VERSION;
87
88 /*
89  * Unfortunately, the kernel prints annoying console messages
90  * in case of an unexpected nfs mount version (instead of
91  * just returning some error).  Therefore we'll have to try
92  * and figure out what version the kernel expects.
93  *
94  * Variables:
95  *      KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
96  *      NFS_MOUNT_VERSION: these nfsmount sources at compile time
97  *      nfs_mount_version: version this source and running kernel can handle
98  */
99 static void find_kernel_nfs_mount_version(void)
100 {
101         int kernel_version = linux_version_code();
102
103         if (kernel_version) {
104                 if (kernel_version < MAKE_VERSION(2, 1, 32))
105                         nfs_mount_version = 1;
106                 else
107                         nfs_mount_version = 3;
108         }
109         if (nfs_mount_version > NFS_MOUNT_VERSION)
110                 nfs_mount_version = NFS_MOUNT_VERSION;
111 }
112
113 int nfsmount(const char *spec, const char *node, unsigned long *flags,
114                          char **extra_opts, char **mount_opts, int running_bg)
115 {
116         static char *prev_bg_host;
117         char hostdir[1024];
118         CLIENT *mclient;
119         char *hostname;
120         char *dirname;
121         char *old_opts;
122         char *mounthost = NULL;
123         char new_opts[1024];
124         fhandle root_fhandle;
125         struct timeval total_timeout;
126         enum clnt_stat clnt_stat;
127         static struct nfs_mount_data data;
128         char *opt, *opteq;
129         int val;
130         struct hostent *hp;
131         struct sockaddr_in server_addr;
132         struct sockaddr_in mount_server_addr;
133         int msock, fsock;
134         struct timeval retry_timeout;
135         struct fhstatus status;
136         struct stat statbuf;
137         char *s;
138         int port;
139         int mountport;
140         int bg;
141         int soft;
142         int intr;
143         int posix;
144         int nocto;
145         int noac;
146         int nolock;
147         int retry;
148         int tcp;
149         int mountprog;
150         int mountvers;
151         int nfsprog;
152         int nfsvers;
153         int retval;
154         time_t t;
155         time_t prevt;
156         time_t timeout;
157
158         find_kernel_nfs_mount_version();
159
160         retval = EX_FAIL;
161         msock = fsock = -1;
162         mclient = NULL;
163         if (strlen(spec) >= sizeof(hostdir)) {
164                 fprintf(stderr, _("mount: "
165                                                   "excessively long host:dir argument\n"));
166                 goto fail;
167         }
168         strcpy(hostdir, spec);
169         if ((s = strchr(hostdir, ':'))) {
170                 hostname = hostdir;
171                 dirname = s + 1;
172                 *s = '\0';
173                 /* Ignore all but first hostname in replicated mounts
174                    until they can be fully supported. (mack@sgi.com) */
175                 if ((s = strchr(hostdir, ','))) {
176                         *s = '\0';
177                         fprintf(stderr, _("mount: warning: "
178                                                           "multiple hostnames not supported\n"));
179                 }
180         } else {
181                 fprintf(stderr, _("mount: "
182                                                   "directory to mount not in host:dir format\n"));
183                 goto fail;
184         }
185
186         server_addr.sin_family = AF_INET;
187 #ifdef HAVE_inet_aton
188         if (!inet_aton(hostname, &server_addr.sin_addr))
189 #endif
190         {
191                 if ((hp = gethostbyname(hostname)) == NULL) {
192                         fprintf(stderr, _("mount: can't get address for %s\n"),
193                                         hostname);
194                         goto fail;
195                 } else {
196                         if (hp->h_length > sizeof(struct in_addr)) {
197                                 fprintf(stderr, _("mount: got bad hp->h_length\n"));
198                                 hp->h_length = sizeof(struct in_addr);
199                         }
200                         memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
201                 }
202         }
203
204         memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
205
206         /* add IP address to mtab options for use when unmounting */
207
208         s = inet_ntoa(server_addr.sin_addr);
209         old_opts = *extra_opts;
210         if (!old_opts)
211                 old_opts = "";
212         if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
213                 fprintf(stderr, _("mount: " "excessively long option argument\n"));
214                 goto fail;
215         }
216         sprintf(new_opts, "%s%saddr=%s", old_opts, *old_opts ? "," : "", s);
217         *extra_opts = xstrdup(new_opts);
218
219         /* Set default options.
220          * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
221          * let the kernel decide.
222          * timeo is filled in after we know whether it'll be TCP or UDP. */
223         memset(&data, 0, sizeof(data));
224         data.retrans = 3;
225         data.acregmin = 3;
226         data.acregmax = 60;
227         data.acdirmin = 30;
228         data.acdirmax = 60;
229 #if NFS_MOUNT_VERSION >= 2
230         data.namlen = NAME_MAX;
231 #endif
232
233         bg = 0;
234         soft = 0;
235         intr = 0;
236         posix = 0;
237         nocto = 0;
238         nolock = 0;
239         noac = 0;
240         retry = 10000;                          /* 10000 minutes ~ 1 week */
241         tcp = 0;
242
243         mountprog = MOUNTPROG;
244         mountvers = MOUNTVERS;
245         port = 0;
246         mountport = 0;
247         nfsprog = NFS_PROGRAM;
248         nfsvers = NFS_VERSION;
249
250         /* parse options */
251
252         for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
253                 if ((opteq = strchr(opt, '='))) {
254                         val = atoi(opteq + 1);
255                         *opteq = '\0';
256                         if (!strcmp(opt, "rsize"))
257                                 data.rsize = val;
258                         else if (!strcmp(opt, "wsize"))
259                                 data.wsize = val;
260                         else if (!strcmp(opt, "timeo"))
261                                 data.timeo = val;
262                         else if (!strcmp(opt, "retrans"))
263                                 data.retrans = val;
264                         else if (!strcmp(opt, "acregmin"))
265                                 data.acregmin = val;
266                         else if (!strcmp(opt, "acregmax"))
267                                 data.acregmax = val;
268                         else if (!strcmp(opt, "acdirmin"))
269                                 data.acdirmin = val;
270                         else if (!strcmp(opt, "acdirmax"))
271                                 data.acdirmax = val;
272                         else if (!strcmp(opt, "actimeo")) {
273                                 data.acregmin = val;
274                                 data.acregmax = val;
275                                 data.acdirmin = val;
276                                 data.acdirmax = val;
277                         } else if (!strcmp(opt, "retry"))
278                                 retry = val;
279                         else if (!strcmp(opt, "port"))
280                                 port = val;
281                         else if (!strcmp(opt, "mountport"))
282                                 mountport = val;
283                         else if (!strcmp(opt, "mounthost"))
284                                 mounthost = xstrndup(opteq + 1,
285                                                                          strcspn(opteq + 1, " \t\n\r,"));
286                         else if (!strcmp(opt, "mountprog"))
287                                 mountprog = val;
288                         else if (!strcmp(opt, "mountvers"))
289                                 mountvers = val;
290                         else if (!strcmp(opt, "nfsprog"))
291                                 nfsprog = val;
292                         else if (!strcmp(opt, "nfsvers") || !strcmp(opt, "vers"))
293                                 nfsvers = val;
294                         else if (!strcmp(opt, "proto")) {
295                                 if (!strncmp(opteq + 1, "tcp", 3))
296                                         tcp = 1;
297                                 else if (!strncmp(opteq + 1, "udp", 3))
298                                         tcp = 0;
299                                 else
300                                         printf(_("Warning: Unrecognized proto= option.\n"));
301                         } else if (!strcmp(opt, "namlen")) {
302 #if NFS_MOUNT_VERSION >= 2
303                                 if (nfs_mount_version >= 2)
304                                         data.namlen = val;
305                                 else
306 #endif
307                                         printf(_
308                                                    ("Warning: Option namlen is not supported.\n"));
309                         } else if (!strcmp(opt, "addr"))
310                                 /* ignore */ ;
311                         else {
312                                 printf(_("unknown nfs mount parameter: "
313                                                  "%s=%d\n"), opt, val);
314                                 goto fail;
315                         }
316                 } else {
317                         val = 1;
318                         if (!strncmp(opt, "no", 2)) {
319                                 val = 0;
320                                 opt += 2;
321                         }
322                         if (!strcmp(opt, "bg"))
323                                 bg = val;
324                         else if (!strcmp(opt, "fg"))
325                                 bg = !val;
326                         else if (!strcmp(opt, "soft"))
327                                 soft = val;
328                         else if (!strcmp(opt, "hard"))
329                                 soft = !val;
330                         else if (!strcmp(opt, "intr"))
331                                 intr = val;
332                         else if (!strcmp(opt, "posix"))
333                                 posix = val;
334                         else if (!strcmp(opt, "cto"))
335                                 nocto = !val;
336                         else if (!strcmp(opt, "ac"))
337                                 noac = !val;
338                         else if (!strcmp(opt, "tcp"))
339                                 tcp = val;
340                         else if (!strcmp(opt, "udp"))
341                                 tcp = !val;
342                         else if (!strcmp(opt, "lock")) {
343                                 if (nfs_mount_version >= 3)
344                                         nolock = !val;
345                                 else
346                                         printf(_
347                                                    ("Warning: option nolock is not supported.\n"));
348                         } else {
349                                 if (!sloppy) {
350                                         printf(_("unknown nfs mount option: "
351                                                          "%s%s\n"), val ? "" : "no", opt);
352                                         goto fail;
353                                 }
354                         }
355                 }
356         }
357         data.flags = (soft ? NFS_MOUNT_SOFT : 0)
358                 | (intr ? NFS_MOUNT_INTR : 0)
359                 | (posix ? NFS_MOUNT_POSIX : 0)
360                 | (nocto ? NFS_MOUNT_NOCTO : 0)
361                 | (noac ? NFS_MOUNT_NOAC : 0);
362 #if NFS_MOUNT_VERSION >= 2
363         if (nfs_mount_version >= 2)
364                 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
365 #endif
366 #if NFS_MOUNT_VERSION >= 3
367         if (nfs_mount_version >= 3)
368                 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
369 #endif
370
371         /* Adjust options if none specified */
372         if (!data.timeo)
373                 data.timeo = tcp ? 70 : 7;
374
375 #ifdef NFS_MOUNT_DEBUG
376         printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
377                    data.rsize, data.wsize, data.timeo, data.retrans);
378         printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
379                    data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
380         printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
381                    port, bg, retry, data.flags);
382         printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
383                    mountprog, mountvers, nfsprog, nfsvers);
384         printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
385                    (data.flags & NFS_MOUNT_SOFT) != 0,
386                    (data.flags & NFS_MOUNT_INTR) != 0,
387                    (data.flags & NFS_MOUNT_POSIX) != 0,
388                    (data.flags & NFS_MOUNT_NOCTO) != 0,
389                    (data.flags & NFS_MOUNT_NOAC) != 0);
390 #if NFS_MOUNT_VERSION >= 2
391         printf("tcp = %d\n", (data.flags & NFS_MOUNT_TCP) != 0);
392 #endif
393 #endif
394
395         data.version = nfs_mount_version;
396         *mount_opts = (char *) &data;
397
398         if (*flags & MS_REMOUNT)
399                 return 0;
400
401         /*
402          * If the previous mount operation on the same host was
403          * backgrounded, and the "bg" for this mount is also set,
404          * give up immediately, to avoid the initial timeout.
405          */
406         if (bg && !running_bg &&
407                 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
408                 if (retry > 0)
409                         retval = EX_BG;
410                 return retval;
411         }
412
413         /* create mount deamon client */
414         /* See if the nfs host = mount host. */
415         if (mounthost) {
416                 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
417                         mount_server_addr.sin_family = AF_INET;
418                         mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
419                 } else {
420                         if ((hp = gethostbyname(mounthost)) == NULL) {
421                                 fprintf(stderr, _("mount: can't get address for %s\n"),
422                                                 hostname);
423                                 goto fail;
424                         } else {
425                                 if (hp->h_length > sizeof(struct in_addr)) {
426                                         fprintf(stderr, _("mount: got bad hp->h_length?\n"));
427                                         hp->h_length = sizeof(struct in_addr);
428                                 }
429                                 mount_server_addr.sin_family = AF_INET;
430                                 memcpy(&mount_server_addr.sin_addr,
431                                            hp->h_addr, hp->h_length);
432                         }
433                 }
434         }
435
436         /*
437          * The following loop implements the mount retries. On the first
438          * call, "running_bg" is 0. When the mount times out, and the
439          * "bg" option is set, the exit status EX_BG will be returned.
440          * For a backgrounded mount, there will be a second call by the
441          * child process with "running_bg" set to 1.
442          *
443          * The case where the mount point is not present and the "bg"
444          * option is set, is treated as a timeout. This is done to
445          * support nested mounts.
446          *
447          * The "retry" count specified by the user is the number of
448          * minutes to retry before giving up.
449          *
450          * Only the first error message will be displayed.
451          */
452         retry_timeout.tv_sec = 3;
453         retry_timeout.tv_usec = 0;
454         total_timeout.tv_sec = 20;
455         total_timeout.tv_usec = 0;
456         timeout = time(NULL) + 60 * retry;
457         prevt = 0;
458         t = 30;
459         val = 1;
460         for (;;) {
461                 if (bg && stat(node, &statbuf) == -1) {
462                         if (running_bg) {
463                                 sleep(val);             /* 1, 2, 4, 8, 16, 30, ... */
464                                 val *= 2;
465                                 if (val > 30)
466                                         val = 30;
467                         }
468                 } else {
469                         /* be careful not to use too many CPU cycles */
470                         if (t - prevt < 30)
471                                 sleep(30);
472
473                         /* contact the mount daemon via TCP */
474                         mount_server_addr.sin_port = htons(mountport);
475                         msock = RPC_ANYSOCK;
476                         mclient = clnttcp_create(&mount_server_addr,
477                                                                          mountprog, mountvers, &msock, 0, 0);
478
479                         /* if this fails, contact the mount daemon via UDP */
480                         if (!mclient) {
481                                 mount_server_addr.sin_port = htons(mountport);
482                                 msock = RPC_ANYSOCK;
483                                 mclient = clntudp_create(&mount_server_addr,
484                                                                                  mountprog, mountvers,
485                                                                                  retry_timeout, &msock);
486                         }
487                         if (mclient) {
488                                 /* try to mount hostname:dirname */
489                                 mclient->cl_auth = authunix_create_default();
490                                 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
491                                                                           (xdrproc_t) xdr_dirpath,
492                                                                           (caddr_t) & dirname,
493                                                                           (xdrproc_t) xdr_fhstatus,
494                                                                           (caddr_t) & status, total_timeout);
495                                 if (clnt_stat == RPC_SUCCESS)
496                                         break;          /* we're done */
497                                 if (errno != ECONNREFUSED) {
498                                         clnt_perror(mclient, "mount");
499                                         goto fail;      /* don't retry */
500                                 }
501                                 if (!running_bg && prevt == 0)
502                                         clnt_perror(mclient, "mount");
503                                 auth_destroy(mclient->cl_auth);
504                                 clnt_destroy(mclient);
505                                 mclient = 0;
506                                 close(msock);
507                         } else {
508                                 if (!running_bg && prevt == 0)
509                                         clnt_pcreateerror("mount");
510                         }
511                         prevt = t;
512                 }
513                 if (!bg)
514                         goto fail;
515                 if (!running_bg) {
516                         prev_bg_host = xstrdup(hostname);
517                         if (retry > 0)
518                                 retval = EX_BG;
519                         goto fail;
520                 }
521                 t = time(NULL);
522                 if (t >= timeout)
523                         goto fail;
524         }
525
526         if (status.fhs_status != 0) {
527                 fprintf(stderr,
528                                 _("mount: %s:%s failed, reason given by server: %s\n"),
529                                 hostname, dirname, nfs_strerror(status.fhs_status));
530                 goto fail;
531         }
532         memcpy((char *) &root_fhandle, (char *) status.fhstatus_u.fhs_fhandle,
533                    sizeof(root_fhandle));
534
535         /* create nfs socket for kernel */
536
537         if (tcp) {
538                 if (nfs_mount_version < 3) {
539                         printf(_("NFS over TCP is not supported.\n"));
540                         goto fail;
541                 }
542                 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
543         } else
544                 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
545         if (fsock < 0) {
546                 perror(_("nfs socket"));
547                 goto fail;
548         }
549         if (bindresvport(fsock, 0) < 0) {
550                 perror(_("nfs bindresvport"));
551                 goto fail;
552         }
553         if (port == 0) {
554                 server_addr.sin_port = PMAPPORT;
555                 port = pmap_getport(&server_addr, nfsprog, nfsvers,
556                                                         tcp ? IPPROTO_TCP : IPPROTO_UDP);
557                 if (port == 0)
558                         port = NFS_PORT;
559 #ifdef NFS_MOUNT_DEBUG
560                 else
561                         printf(_("used portmapper to find NFS port\n"));
562 #endif
563         }
564 #ifdef NFS_MOUNT_DEBUG
565         printf(_("using port %d for nfs deamon\n"), port);
566 #endif
567         server_addr.sin_port = htons(port);
568         /*
569          * connect() the socket for kernels 1.3.10 and below only,
570          * to avoid problems with multihomed hosts.
571          * --Swen
572          */
573         if (linux_version_code() <= 66314
574                 && connect(fsock, (struct sockaddr *) &server_addr,
575                                    sizeof(server_addr)) < 0) {
576                 perror(_("nfs connect"));
577                 goto fail;
578         }
579
580         /* prepare data structure for kernel */
581
582         data.fd = fsock;
583         memcpy((char *) &data.root, (char *) &root_fhandle,
584                    sizeof(root_fhandle));
585         memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
586         strncpy(data.hostname, hostname, sizeof(data.hostname));
587
588         /* clean up */
589
590         auth_destroy(mclient->cl_auth);
591         clnt_destroy(mclient);
592         close(msock);
593         return 0;
594
595         /* abort */
596
597   fail:
598         if (msock != -1) {
599                 if (mclient) {
600                         auth_destroy(mclient->cl_auth);
601                         clnt_destroy(mclient);
602                 }
603                 close(msock);
604         }
605         if (fsock != -1)
606                 close(fsock);
607         return retval;
608 }
609
610 /*
611  * We need to translate between nfs status return values and
612  * the local errno values which may not be the same.
613  *
614  * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
615  * "after #include <errno.h> the symbol errno is reserved for any use,
616  *  it cannot even be used as a struct tag or field name".
617  */
618
619 #ifndef EDQUOT
620 #define EDQUOT  ENOSPC
621 #endif
622
623 static struct {
624         enum nfs_stat stat;
625         int errnum;
626 } nfs_errtbl[] = {
627         {
628         NFS_OK, 0}, {
629         NFSERR_PERM, EPERM}, {
630         NFSERR_NOENT, ENOENT}, {
631         NFSERR_IO, EIO}, {
632         NFSERR_NXIO, ENXIO}, {
633         NFSERR_ACCES, EACCES}, {
634         NFSERR_EXIST, EEXIST}, {
635         NFSERR_NODEV, ENODEV}, {
636         NFSERR_NOTDIR, ENOTDIR}, {
637         NFSERR_ISDIR, EISDIR},
638 #ifdef NFSERR_INVAL
639         {
640         NFSERR_INVAL, EINVAL},          /* that Sun forgot */
641 #endif
642         {
643         NFSERR_FBIG, EFBIG}, {
644         NFSERR_NOSPC, ENOSPC}, {
645         NFSERR_ROFS, EROFS}, {
646         NFSERR_NAMETOOLONG, ENAMETOOLONG}, {
647         NFSERR_NOTEMPTY, ENOTEMPTY}, {
648         NFSERR_DQUOT, EDQUOT}, {
649         NFSERR_STALE, ESTALE},
650 #ifdef EWFLUSH
651         {
652         NFSERR_WFLUSH, EWFLUSH},
653 #endif
654                 /* Throw in some NFSv3 values for even more fun (HP returns these) */
655         {
656         71, EREMOTE}, {
657         -1, EIO}
658 };
659
660 static char *nfs_strerror(int stat)
661 {
662         int i;
663         static char buf[256];
664
665         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
666                 if (nfs_errtbl[i].stat == stat)
667                         return strerror(nfs_errtbl[i].errnum);
668         }
669         sprintf(buf, _("unknown nfs status return value: %d"), stat);
670         return buf;
671 }
672
673 #if 0
674 int my_getport(struct in_addr server, struct timeval *timeo, ...)
675 {
676         struct sockaddr_in sin;
677         struct pmap pmap;
678         CLIENT *clnt;
679         int sock = RPC_ANYSOCK, port;
680
681         pmap.pm_prog = prog;
682         pmap.pm_vers = vers;
683         pmap.pm_prot = prot;
684         pmap.pm_port = 0;
685         sin.sin_family = AF_INET;
686         sin.sin_addr = server;
687         sin.sin_port = htons(111);
688         clnt = clntudp_create(&sin, 100000, 2, *timeo, &sock);
689         status = clnt_call(clnt, PMAP_GETPORT,
690                                            &pmap, (xdrproc_t) xdr_pmap,
691                                            &port, (xdrproc_t) xdr_uint);
692         if (status != SUCCESS) {
693                 /* natter */
694                 port = 0;
695         }
696
697         clnt_destroy(clnt);
698         close(sock);
699         return port;
700 }
701 #endif
702
703
704
705
706
707
708
709
710
711
712
713 /*
714  * Please do not edit this file.
715  * It was generated using rpcgen.
716  */
717
718 #include <rpc/types.h>
719 #include <rpc/xdr.h>
720
721 /*
722  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
723  * unrestricted use provided that this legend is included on all tape
724  * media and as a part of the software program in whole or part.  Users
725  * may copy or modify Sun RPC without charge, but are not authorized
726  * to license or distribute it to anyone else except as part of a product or
727  * program developed by the user or with the express written consent of
728  * Sun Microsystems, Inc.
729  *
730  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
731  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
732  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
733  *
734  * Sun RPC is provided with no support and without any obligation on the
735  * part of Sun Microsystems, Inc. to assist in its use, correction,
736  * modification or enhancement.
737  *
738  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
739  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
740  * OR ANY PART THEREOF.
741  *
742  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
743  * or profits or other special, indirect and consequential damages, even if
744  * Sun has been advised of the possibility of such damages.
745  *
746  * Sun Microsystems, Inc.
747  * 2550 Garcia Avenue
748  * Mountain View, California  94043
749  */
750 /*
751  * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
752  */
753
754 /* from @(#)mount.x     1.3 91/03/11 TIRPC 1.0 */
755
756 bool_t xdr_fhandle(XDR * xdrs, fhandle objp)
757 {
758
759         if (!xdr_opaque(xdrs, objp, FHSIZE)) {
760                 return (FALSE);
761         }
762         return (TRUE);
763 }
764
765 bool_t xdr_fhstatus(XDR * xdrs, fhstatus * objp)
766 {
767
768         if (!xdr_u_int(xdrs, &objp->fhs_status)) {
769                 return (FALSE);
770         }
771         switch (objp->fhs_status) {
772         case 0:
773                 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) {
774                         return (FALSE);
775                 }
776                 break;
777         default:
778                 break;
779         }
780         return (TRUE);
781 }
782
783 bool_t xdr_dirpath(XDR * xdrs, dirpath * objp)
784 {
785
786         if (!xdr_string(xdrs, objp, MNTPATHLEN)) {
787                 return (FALSE);
788         }
789         return (TRUE);
790 }
791
792 bool_t xdr_name(XDR * xdrs, name * objp)
793 {
794
795         if (!xdr_string(xdrs, objp, MNTNAMLEN)) {
796                 return (FALSE);
797         }
798         return (TRUE);
799 }
800
801 bool_t xdr_mountlist(XDR * xdrs, mountlist * objp)
802 {
803
804         if (!xdr_pointer
805                 (xdrs, (char **) objp, sizeof(struct mountbody),
806                  (xdrproc_t) xdr_mountbody)) {
807                 return (FALSE);
808         }
809         return (TRUE);
810 }
811
812 bool_t xdr_mountbody(XDR * xdrs, mountbody * objp)
813 {
814
815         if (!xdr_name(xdrs, &objp->ml_hostname)) {
816                 return (FALSE);
817         }
818         if (!xdr_dirpath(xdrs, &objp->ml_directory)) {
819                 return (FALSE);
820         }
821         if (!xdr_mountlist(xdrs, &objp->ml_next)) {
822                 return (FALSE);
823         }
824         return (TRUE);
825 }
826
827 bool_t xdr_groups(XDR * xdrs, groups * objp)
828 {
829
830         if (!xdr_pointer
831                 (xdrs, (char **) objp, sizeof(struct groupnode),
832                  (xdrproc_t) xdr_groupnode)) {
833                 return (FALSE);
834         }
835         return (TRUE);
836 }
837
838 bool_t xdr_groupnode(XDR * xdrs, groupnode * objp)
839 {
840
841         if (!xdr_name(xdrs, &objp->gr_name)) {
842                 return (FALSE);
843         }
844         if (!xdr_groups(xdrs, &objp->gr_next)) {
845                 return (FALSE);
846         }
847         return (TRUE);
848 }
849
850 bool_t xdr_exports(XDR * xdrs, exports * objp)
851 {
852
853         if (!xdr_pointer
854                 (xdrs, (char **) objp, sizeof(struct exportnode),
855                  (xdrproc_t) xdr_exportnode)) {
856                 return (FALSE);
857         }
858         return (TRUE);
859 }
860
861 bool_t xdr_exportnode(XDR * xdrs, exportnode * objp)
862 {
863
864         if (!xdr_dirpath(xdrs, &objp->ex_dir)) {
865                 return (FALSE);
866         }
867         if (!xdr_groups(xdrs, &objp->ex_groups)) {
868                 return (FALSE);
869         }
870         if (!xdr_exports(xdrs, &objp->ex_next)) {
871                 return (FALSE);
872         }
873         return (TRUE);
874 }
875
876 bool_t xdr_ppathcnf(XDR * xdrs, ppathcnf * objp)
877 {
878
879         register long *buf;
880
881         int i;
882
883         if (xdrs->x_op == XDR_ENCODE) {
884                 buf = (long *) XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
885                 if (buf == NULL) {
886                         if (!xdr_int(xdrs, &objp->pc_link_max)) {
887                                 return (FALSE);
888                         }
889                         if (!xdr_short(xdrs, &objp->pc_max_canon)) {
890                                 return (FALSE);
891                         }
892                         if (!xdr_short(xdrs, &objp->pc_max_input)) {
893                                 return (FALSE);
894                         }
895                         if (!xdr_short(xdrs, &objp->pc_name_max)) {
896                                 return (FALSE);
897                         }
898                         if (!xdr_short(xdrs, &objp->pc_path_max)) {
899                                 return (FALSE);
900                         }
901                         if (!xdr_short(xdrs, &objp->pc_pipe_buf)) {
902                                 return (FALSE);
903                         }
904
905                 } else {
906                         IXDR_PUT_LONG(buf, objp->pc_link_max);
907                         IXDR_PUT_SHORT(buf, objp->pc_max_canon);
908                         IXDR_PUT_SHORT(buf, objp->pc_max_input);
909                         IXDR_PUT_SHORT(buf, objp->pc_name_max);
910                         IXDR_PUT_SHORT(buf, objp->pc_path_max);
911                         IXDR_PUT_SHORT(buf, objp->pc_pipe_buf);
912                 }
913                 if (!xdr_u_char(xdrs, &objp->pc_vdisable)) {
914                         return (FALSE);
915                 }
916                 if (!xdr_char(xdrs, &objp->pc_xxx)) {
917                         return (FALSE);
918                 }
919                 buf = (long *) XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
920                 if (buf == NULL) {
921                         if (!xdr_vector
922                                 (xdrs, (char *) objp->pc_mask, 2, sizeof(short),
923                                  (xdrproc_t) xdr_short)) {
924                                 return (FALSE);
925                         }
926
927                 } else {
928                         {
929                                 register short *genp;
930
931                                 for (i = 0, genp = objp->pc_mask; i < 2; i++) {
932                                         IXDR_PUT_SHORT(buf, *genp++);
933                                 }
934                         };
935                 }
936
937                 return (TRUE);
938         } else if (xdrs->x_op == XDR_DECODE) {
939                 buf = (long *) XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
940                 if (buf == NULL) {
941                         if (!xdr_int(xdrs, &objp->pc_link_max)) {
942                                 return (FALSE);
943                         }
944                         if (!xdr_short(xdrs, &objp->pc_max_canon)) {
945                                 return (FALSE);
946                         }
947                         if (!xdr_short(xdrs, &objp->pc_max_input)) {
948                                 return (FALSE);
949                         }
950                         if (!xdr_short(xdrs, &objp->pc_name_max)) {
951                                 return (FALSE);
952                         }
953                         if (!xdr_short(xdrs, &objp->pc_path_max)) {
954                                 return (FALSE);
955                         }
956                         if (!xdr_short(xdrs, &objp->pc_pipe_buf)) {
957                                 return (FALSE);
958                         }
959
960                 } else {
961                         objp->pc_link_max = IXDR_GET_LONG(buf);
962                         objp->pc_max_canon = IXDR_GET_SHORT(buf);
963                         objp->pc_max_input = IXDR_GET_SHORT(buf);
964                         objp->pc_name_max = IXDR_GET_SHORT(buf);
965                         objp->pc_path_max = IXDR_GET_SHORT(buf);
966                         objp->pc_pipe_buf = IXDR_GET_SHORT(buf);
967                 }
968                 if (!xdr_u_char(xdrs, &objp->pc_vdisable)) {
969                         return (FALSE);
970                 }
971                 if (!xdr_char(xdrs, &objp->pc_xxx)) {
972                         return (FALSE);
973                 }
974                 buf = (long *) XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
975                 if (buf == NULL) {
976                         if (!xdr_vector
977                                 (xdrs, (char *) objp->pc_mask, 2, sizeof(short),
978                                  (xdrproc_t) xdr_short)) {
979                                 return (FALSE);
980                         }
981
982                 } else {
983                         {
984                                 register short *genp;
985
986                                 for (i = 0, genp = objp->pc_mask; i < 2; i++) {
987                                         *genp++ = IXDR_GET_SHORT(buf);
988                                 }
989                         };
990                 }
991                 return (TRUE);
992         }
993
994         if (!xdr_int(xdrs, &objp->pc_link_max)) {
995                 return (FALSE);
996         }
997         if (!xdr_short(xdrs, &objp->pc_max_canon)) {
998                 return (FALSE);
999         }
1000         if (!xdr_short(xdrs, &objp->pc_max_input)) {
1001                 return (FALSE);
1002         }
1003         if (!xdr_short(xdrs, &objp->pc_name_max)) {
1004                 return (FALSE);
1005         }
1006         if (!xdr_short(xdrs, &objp->pc_path_max)) {
1007                 return (FALSE);
1008         }
1009         if (!xdr_short(xdrs, &objp->pc_pipe_buf)) {
1010                 return (FALSE);
1011         }
1012         if (!xdr_u_char(xdrs, &objp->pc_vdisable)) {
1013                 return (FALSE);
1014         }
1015         if (!xdr_char(xdrs, &objp->pc_xxx)) {
1016                 return (FALSE);
1017         }
1018         if (!xdr_vector
1019                 (xdrs, (char *) objp->pc_mask, 2, sizeof(short),
1020                  (xdrproc_t) xdr_short)) {
1021                 return (FALSE);
1022         }
1023         return (TRUE);
1024 }
1025
1026
1027 /*
1028  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
1029  * unrestricted use provided that this legend is included on all tape
1030  * media and as a part of the software program in whole or part.  Users
1031  * may copy or modify Sun RPC without charge, but are not authorized
1032  * to license or distribute it to anyone else except as part of a product or
1033  * program developed by the user or with the express written consent of
1034  * Sun Microsystems, Inc.
1035  *
1036  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1037  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1038  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1039  *
1040  * Sun RPC is provided with no support and without any obligation on the
1041  * part of Sun Microsystems, Inc. to assist in its use, correction,
1042  * modification or enhancement.
1043  *
1044  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
1045  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
1046  * OR ANY PART THEREOF.
1047  *
1048  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
1049  * or profits or other special, indirect and consequential damages, even if
1050  * Sun has been advised of the possibility of such damages.
1051  *
1052  * Sun Microsystems, Inc.
1053  * 2550 Garcia Avenue
1054  * Mountain View, California  94043
1055  */
1056 /*
1057  * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
1058  */
1059
1060 /* from @(#)mount.x     1.3 91/03/11 TIRPC 1.0 */
1061
1062 #include <string.h>                             /* for memset() */
1063
1064 /* Default timeout can be changed using clnt_control() */
1065 static struct timeval TIMEOUT = { 25, 0 };
1066
1067 void *mountproc_null_1(argp, clnt)
1068 void *argp;
1069 CLIENT *clnt;
1070 {
1071         static char clnt_res;
1072
1073         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1074         if (clnt_call
1075                 (clnt, MOUNTPROC_NULL, (xdrproc_t) xdr_void, argp,
1076                  (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
1077                 return (NULL);
1078         }
1079         return ((void *) &clnt_res);
1080 }
1081
1082 fhstatus *mountproc_mnt_1(argp, clnt)
1083 dirpath *argp;
1084 CLIENT *clnt;
1085 {
1086         static fhstatus clnt_res;
1087
1088         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1089         if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath,
1090                                   (caddr_t) argp, (xdrproc_t) xdr_fhstatus,
1091                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1092                 return (NULL);
1093         }
1094         return (&clnt_res);
1095 }
1096
1097 mountlist *mountproc_dump_1(argp, clnt)
1098 void *argp;
1099 CLIENT *clnt;
1100 {
1101         static mountlist clnt_res;
1102
1103         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1104         if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void,
1105                                   (caddr_t) argp, (xdrproc_t) xdr_mountlist,
1106                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1107                 return (NULL);
1108         }
1109         return (&clnt_res);
1110 }
1111
1112 void *mountproc_umnt_1(argp, clnt)
1113 dirpath *argp;
1114 CLIENT *clnt;
1115 {
1116         static char clnt_res;
1117
1118         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1119         if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath,
1120                                   (caddr_t) argp, (xdrproc_t) xdr_void,
1121                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1122                 return (NULL);
1123         }
1124         return ((void *) &clnt_res);
1125 }
1126
1127 void *mountproc_umntall_1(argp, clnt)
1128 void *argp;
1129 CLIENT *clnt;
1130 {
1131         static char clnt_res;
1132
1133         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1134         if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void,
1135                                   (caddr_t) argp, (xdrproc_t) xdr_void,
1136                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1137                 return (NULL);
1138         }
1139         return ((void *) &clnt_res);
1140 }
1141
1142 exports *mountproc_export_1(argp, clnt)
1143 void *argp;
1144 CLIENT *clnt;
1145 {
1146         static exports clnt_res;
1147
1148         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1149         if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void,
1150                                   (caddr_t) argp, (xdrproc_t) xdr_exports,
1151                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1152                 return (NULL);
1153         }
1154         return (&clnt_res);
1155 }
1156
1157 exports *mountproc_exportall_1(argp, clnt)
1158 void *argp;
1159 CLIENT *clnt;
1160 {
1161         static exports clnt_res;
1162
1163         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1164         if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void,
1165                                   (caddr_t) argp, (xdrproc_t) xdr_exports,
1166                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1167                 return (NULL);
1168         }
1169         return (&clnt_res);
1170 }
1171
1172 void *mountproc_null_2(argp, clnt)
1173 void *argp;
1174 CLIENT *clnt;
1175 {
1176         static char clnt_res;
1177
1178         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1179         if (clnt_call
1180                 (clnt, MOUNTPROC_NULL, (xdrproc_t) xdr_void, argp,
1181                  (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
1182                 return (NULL);
1183         }
1184         return ((void *) &clnt_res);
1185 }
1186
1187 fhstatus *mountproc_mnt_2(argp, clnt)
1188 dirpath *argp;
1189 CLIENT *clnt;
1190 {
1191         static fhstatus clnt_res;
1192
1193         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1194         if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath,
1195                                   (caddr_t) argp, (xdrproc_t) xdr_fhstatus,
1196                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1197                 return (NULL);
1198         }
1199         return (&clnt_res);
1200 }
1201
1202 mountlist *mountproc_dump_2(argp, clnt)
1203 void *argp;
1204 CLIENT *clnt;
1205 {
1206         static mountlist clnt_res;
1207
1208         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1209         if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, argp,
1210                                   (xdrproc_t) xdr_mountlist, (caddr_t) & clnt_res,
1211                                   TIMEOUT) != RPC_SUCCESS) {
1212                 return (NULL);
1213         }
1214         return (&clnt_res);
1215 }
1216
1217 void *mountproc_umnt_2(argp, clnt)
1218 dirpath *argp;
1219 CLIENT *clnt;
1220 {
1221         static char clnt_res;
1222
1223         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1224         if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath,
1225                                   (caddr_t) argp, (xdrproc_t) xdr_void,
1226                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1227                 return (NULL);
1228         }
1229         return ((void *) &clnt_res);
1230 }
1231
1232 void *mountproc_umntall_2(argp, clnt)
1233 void *argp;
1234 CLIENT *clnt;
1235 {
1236         static char clnt_res;
1237
1238         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1239         if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void,
1240                                   (caddr_t) argp, (xdrproc_t) xdr_void,
1241                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1242                 return (NULL);
1243         }
1244         return ((void *) &clnt_res);
1245 }
1246
1247 exports *mountproc_export_2(argp, clnt)
1248 void *argp;
1249 CLIENT *clnt;
1250 {
1251         static exports clnt_res;
1252
1253         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1254         if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void,
1255                                   argp, (xdrproc_t) xdr_exports, (caddr_t) & clnt_res,
1256                                   TIMEOUT) != RPC_SUCCESS) {
1257                 return (NULL);
1258         }
1259         return (&clnt_res);
1260 }
1261
1262 exports *mountproc_exportall_2(argp, clnt)
1263 void *argp;
1264 CLIENT *clnt;
1265 {
1266         static exports clnt_res;
1267
1268         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1269         if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, argp,
1270                                   (xdrproc_t) xdr_exports, (caddr_t) & clnt_res,
1271                                   TIMEOUT) != RPC_SUCCESS) {
1272                 return (NULL);
1273         }
1274         return (&clnt_res);
1275 }
1276
1277 ppathcnf *mountproc_pathconf_2(argp, clnt)
1278 dirpath *argp;
1279 CLIENT *clnt;
1280 {
1281         static ppathcnf clnt_res;
1282
1283         memset((char *) &clnt_res, 0, sizeof(clnt_res));
1284         if (clnt_call(clnt, MOUNTPROC_PATHCONF, (xdrproc_t) xdr_dirpath,
1285                                   (caddr_t) argp, (xdrproc_t) xdr_ppathcnf,
1286                                   (caddr_t) & clnt_res, TIMEOUT) != RPC_SUCCESS) {
1287                 return (NULL);
1288         }
1289         return (&clnt_res);
1290 }