📄 nfsmount.c
字号:
/* vi: set sw=4 ts=4: *//* * nfsmount.c -- Linux NFS mount * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port * numbers to be specified on the command line. * * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>: * Omit the call to connect() for Linux version 1.3.11 or later. * * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com> * Implemented the "bg", "fg" and "retry" mount options for NFS. * * 1999-02-22 Arkadiusz Mi秌iewicz <misiek@misiek.eu.org> * - added Native Language Support * * Modified by Olaf Kirch and Trond Myklebust for new NFS code, * plus NFSv3 stuff. *//* * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp */#include <unistd.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <netdb.h>#include <sys/socket.h>#include <time.h>#include <sys/utsname.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <sys/stat.h>#undef TRUE#undef FALSE#include <rpc/rpc.h>#include <rpc/pmap_prot.h>#include <rpc/pmap_clnt.h>#include <linux/nfs.h> /* For the kernels nfs stuff */#include "nfsmount.h"#define error_msg(arg...) fprintf(stderr, arg)#ifndef NFS_FHSIZEstatic const int NFS_FHSIZE = 32;#endif#ifndef NFS_PORTstatic const int NFS_PORT = 2049;#endif/* the bug of tool chain */#define TOOL_CHAIN#ifdef TOOL_CHAIN#include <rpc/types.h>#include <rpc/xdr.h>/* * constants specific to the xdr "protocol" */#define XDR_FALSE ((long) 0)#define XDR_TRUE ((long) 1)#define LASTUNSIGNED ((u_int) 0-1)/* * These are the "generic" xdr routines. */bool_t _xdr_int();#endif /*TOOL_CHAIN*//* Disable the nls stuff */# undef bindtextdomain# define bindtextdomain(Domain, Directory) /* empty */# undef textdomain# define textdomain(Domain) /* empty */# define _(Text) (Text)# define N_(Text) (Text)static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */static const int MS_RDONLY = 1; /* Mount read-only */static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */static const int MS_NODEV = 4; /* Disallow access to device special files */static const int MS_NOEXEC = 8; /* Disallow program execution */static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */static const int S_APPEND = 256; /* Append-only file */static const int S_IMMUTABLE = 512; /* Immutable file */static const int MS_NOATIME = 1024; /* Do not update access times. */static const int MS_NODIRATIME = 2048; /* Do not update directory access times *//* * We want to be able to compile mount on old kernels in such a way * that the binary will work well on more recent kernels. * Thus, if necessary we teach nfsmount.c the structure of new fields * that will come later. * * Moreover, the new kernel includes conflict with glibc includes * so it is easiest to ignore the kernel altogether (at compile time). *//* NOTE: Do not make this into a 'static const int' because the pre-processor * needs to test this value in some #if statements. */#define NFS_MOUNT_VERSION 4struct nfs2_fh { char data[32];};struct nfs3_fh { unsigned short size; unsigned char data[64];};struct nfs_mount_data { int version; /* 1 */ int fd; /* 1 */ struct nfs2_fh old_root; /* 1 */ int flags; /* 1 */ int rsize; /* 1 */ int wsize; /* 1 */ int timeo; /* 1 */ int retrans; /* 1 */ int acregmin; /* 1 */ int acregmax; /* 1 */ int acdirmin; /* 1 */ int acdirmax; /* 1 */ struct sockaddr_in addr; /* 1 */ char hostname[256]; /* 1 */ int namlen; /* 2 */ unsigned int bsize; /* 3 */ struct nfs3_fh root; /* 4 */};/* bits in the flags field */static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */static const int NFS_MOUNT_INTR = 0x0002; /* 1 */static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */static const int NFS_MOUNT_TCP = 0x0040; /* 2 */static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */#define UTIL_LINUX_VERSION "2.10m"#define util_linux_version "util-linux-2.10m"#define HAVE_inet_aton#define HAVE_scsi_h#define HAVE_blkpg_h#define HAVE_kd_h#define HAVE_termcap#define HAVE_locale_h#define HAVE_libintl_h#define ENABLE_NLS#define HAVE_langinfo_h#define HAVE_progname#define HAVE_openpty#define HAVE_nanosleep#define HAVE_personality#define HAVE_tm_gmtoffstatic char *nfs_strerror(int status);#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)static const int EX_FAIL = 32; /* mount failure */static const int EX_BG = 256; /* retry in background (internal only) */char *xstrdup (const char *s);char *xstrndup (const char *s, int n);#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))static intget_kernel_revision(void) { struct utsname my_utsname; int p, q, r; if (uname(&my_utsname) == 0) { p = atoi(strtok(my_utsname.release, ".")); q = atoi(strtok(NULL, ".")); r = atoi(strtok(NULL, ".")); return MAKE_VERSION(p,q,r); } return 0;}/* * nfs_mount_version according to the sources seen at compile time. */static int nfs_mount_version;/* * Unfortunately, the kernel prints annoying console messages * in case of an unexpected nfs mount version (instead of * just returning some error). Therefore we'll have to try * and figure out what version the kernel expects. * * Variables: * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time * NFS_MOUNT_VERSION: these nfsmount sources at compile time * nfs_mount_version: version this source and running kernel can handle */static voidfind_kernel_nfs_mount_version(void){ static int kernel_version = 0; if (kernel_version) return; nfs_mount_version = NFS_MOUNT_VERSION; /* default */ kernel_version = get_kernel_revision(); if (kernel_version) { if (kernel_version < MAKE_VERSION(2,1,32)) nfs_mount_version = 1; else if (kernel_version < MAKE_VERSION(2,2,18) || (kernel_version >= MAKE_VERSION(2,3,0) && kernel_version < MAKE_VERSION(2,3,99))) nfs_mount_version = 3; else nfs_mount_version = 4; /* since 2.3.99pre4 */ } if (nfs_mount_version > NFS_MOUNT_VERSION) nfs_mount_version = NFS_MOUNT_VERSION;}static struct pmap *get_mountport(struct sockaddr_in *server_addr, long unsigned prog, long unsigned version, long unsigned proto, long unsigned port){struct pmaplist *pmap;static struct pmap p = {0, 0, 0, 0};server_addr->sin_port = PMAPPORT;pmap = pmap_getmaps(server_addr);if (version > MAX_NFSPROT) version = MAX_NFSPROT;if (!prog) prog = MOUNTPROG;p.pm_prog = prog;p.pm_vers = version;p.pm_prot = proto;p.pm_port = port;while (pmap) { if (pmap->pml_map.pm_prog != prog) goto next; if (!version && p.pm_vers > pmap->pml_map.pm_vers) goto next; if (version > 2 && pmap->pml_map.pm_vers != version) goto next; if (version && version <= 2 && pmap->pml_map.pm_vers > 2) goto next; if (pmap->pml_map.pm_vers > MAX_NFSPROT || (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || (port && pmap->pml_map.pm_port != port)) goto next; memcpy(&p, &pmap->pml_map, sizeof(p));next: pmap = pmap->pml_next;}if (!p.pm_vers) p.pm_vers = MOUNTVERS;if (!p.pm_port) p.pm_port = MOUNTPORT;if (!p.pm_prot) p.pm_prot = IPPROTO_TCP;return &p;}int nfsmount(const char *spec, const char *node, int *flags, char **extra_opts, char **mount_opts, int running_bg){ static char *prev_bg_host; char hostdir[1024]; CLIENT *mclient; char *hostname; char *dirname; char *old_opts; char *mounthost=NULL; char new_opts[1024]; struct timeval total_timeout; enum clnt_stat clnt_stat; static struct nfs_mount_data data; char *opt, *opteq; int val; struct hostent *hp; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; struct pmap* pm_mnt; int msock, fsock; struct timeval retry_timeout; union { struct fhstatus nfsv2; struct mountres3 nfsv3; } status; struct stat statbuf; char *s; int port; int mountport; int proto; int bg; int soft; int intr; int posix; int nocto; int noac; int nolock; int retry; int tcp; int mountprog; int mountvers; int nfsprog; int nfsvers; int retval; time_t t; time_t prevt; time_t timeout; find_kernel_nfs_mount_version(); retval = EX_FAIL; msock = fsock = -1; mclient = NULL; if (strlen(spec) >= sizeof(hostdir)) { error_msg("excessively long host:dir argument"); goto fail; } strcpy(hostdir, spec); if ((s = strchr(hostdir, ':'))) { hostname = hostdir; dirname = s + 1; *s = '\0'; /* Ignore all but first hostname in replicated mounts until they can be fully supported. (mack@sgi.com) */ if ((s = strchr(hostdir, ','))) { *s = '\0'; error_msg("warning: multiple hostnames not supported"); } } else { error_msg("directory to mount not in host:dir format"); goto fail; } server_addr.sin_family = AF_INET;#ifdef HAVE_inet_aton if (!inet_aton(hostname, &server_addr.sin_addr))#endif {#ifdef NO_GETHOSTBYNAME fprintf(stderr, "ERROR (%d): no gethostbyname()\n", __LINE__);#else if ((hp = gethostbyname(hostname)) == NULL) { error_msg("can't get address for %s", hostname); goto fail; } else { if (hp->h_length > sizeof(struct in_addr)) { error_msg("got bad hp->h_length"); hp->h_length = sizeof(struct in_addr); } memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); }#endif } memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); /* add IP address to mtab options for use when unmounting */ s = inet_ntoa(server_addr.sin_addr); old_opts = *extra_opts; if (!old_opts) old_opts = ""; if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { error_msg("excessively long option argument"); goto fail; } sprintf(new_opts, "%s%saddr=%s", old_opts, *old_opts ? "," : "", s); *extra_opts = xstrdup(new_opts); /* Set default options. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to * let the kernel decide. * timeo is filled in after we know whether it'll be TCP or UDP. */ memset(&data, 0, sizeof(data)); data.retrans = 3; data.acregmin = 3; data.acregmax = 60; data.acdirmin = 30; data.acdirmax = 60;#if NFS_MOUNT_VERSION >= 2 data.namlen = NAME_MAX;#endif bg = 0; soft = 0; intr = 0; posix = 0; nocto = 0; nolock = 0; noac = 0; retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 0; mountprog = MOUNTPROG; mountvers = 0; port = 0; mountport = 0; nfsprog = NFS_PROGRAM; nfsvers = 0; /* parse options */ for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { if ((opteq = strchr(opt, '='))) { val = atoi(opteq + 1); *opteq = '\0'; if (!strcmp(opt, "rsize")) data.rsize = val; else if (!strcmp(opt, "wsize")) data.wsize = val; else if (!strcmp(opt, "timeo")) data.timeo = val; else if (!strcmp(opt, "retrans")) data.retrans = val; else if (!strcmp(opt, "acregmin")) data.acregmin = val; else if (!strcmp(opt, "acregmax")) data.acregmax = val; else if (!strcmp(opt, "acdirmin")) data.acdirmin = val; else if (!strcmp(opt, "acdirmax")) data.acdirmax = val; else if (!strcmp(opt, "actimeo")) { data.acregmin = val; data.acregmax = val; data.acdirmin = val; data.acdirmax = val; } else if (!strcmp(opt, "retry")) retry = val; else if (!strcmp(opt, "port")) port = val; else if (!strcmp(opt, "mountport")) mountport = val; else if (!strcmp(opt, "mounthost")) mounthost=xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,")); else if (!strcmp(opt, "mountprog")) mountprog = val; else if (!strcmp(opt, "mountvers")) mountvers = val; else if (!strcmp(opt, "nfsprog")) nfsprog = val; else if (!strcmp(opt, "nfsvers") || !strcmp(opt, "vers")) nfsvers = val; else if (!strcmp(opt, "proto")) { if (!strncmp(opteq+1, "tcp", 3)) tcp = 1; else if (!strncmp(opteq+1, "udp", 3)) tcp = 0; else printf(_("Warning: Unrecognized proto= option.\n")); } else if (!strcmp(opt, "namlen")) {#if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.namlen = val; else#endif printf(_("Warning: Option namlen is not supported.\n")); } else if (!strcmp(opt, "addr")) /* ignore */; else { printf(_("unknown nfs mount parameter: " "%s=%d\n"), opt, val); goto fail; } } else { val = 1; if (!strncmp(opt, "no", 2)) { val = 0; opt += 2; } if (!strcmp(opt, "bg")) bg = val; else if (!strcmp(opt, "fg")) bg = !val; else if (!strcmp(opt, "soft")) soft = val; else if (!strcmp(opt, "hard")) soft = !val; else if (!strcmp(opt, "intr")) intr = val; else if (!strcmp(opt, "posix")) posix = val; else if (!strcmp(opt, "cto"))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -