📄 nfsmount.c
字号:
nocto = !val; else if (!strcmp(opt, "ac")) noac = !val; else if (!strcmp(opt, "tcp")) tcp = val; else if (!strcmp(opt, "udp")) tcp = !val; else if (!strcmp(opt, "lock")) { if (nfs_mount_version >= 3) nolock = !val; else printf(_("Warning: option nolock is not supported.\n")); } else { printf(_("unknown nfs mount option: " "%s%s\n"), val ? "" : "no", opt); goto fail; } } } proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; data.flags = (soft ? NFS_MOUNT_SOFT : 0) | (intr ? NFS_MOUNT_INTR : 0) | (posix ? NFS_MOUNT_POSIX : 0) | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0);#if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.flags |= (tcp ? NFS_MOUNT_TCP : 0);#endif#if NFS_MOUNT_VERSION >= 3 if (nfs_mount_version >= 3) data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);#endif if (nfsvers > MAX_NFSPROT) { error_msg("NFSv%d not supported!", nfsvers); return 0; } if (mountvers > MAX_NFSPROT) { error_msg("NFSv%d not supported!", nfsvers); return 0; } if (nfsvers && !mountvers) mountvers = (nfsvers < 3) ? 1 : nfsvers; if (nfsvers && nfsvers < mountvers) { mountvers = nfsvers; } /* Adjust options if none specified */ if (!data.timeo) data.timeo = tcp ? 70 : 7;#ifdef NFS_MOUNT_DEBUG printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", data.rsize, data.wsize, data.timeo, data.retrans); printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", port, bg, retry, data.flags); printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", mountprog, mountvers, nfsprog, nfsvers); printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", (data.flags & NFS_MOUNT_SOFT) != 0, (data.flags & NFS_MOUNT_INTR) != 0, (data.flags & NFS_MOUNT_POSIX) != 0, (data.flags & NFS_MOUNT_NOCTO) != 0, (data.flags & NFS_MOUNT_NOAC) != 0);#if NFS_MOUNT_VERSION >= 2 printf("tcp = %d\n", (data.flags & NFS_MOUNT_TCP) != 0);#endif#endif data.version = nfs_mount_version; *mount_opts = (char *) &data; if (*flags & MS_REMOUNT) return 0; /* * If the previous mount operation on the same host was * backgrounded, and the "bg" for this mount is also set, * give up immediately, to avoid the initial timeout. */ if (bg && !running_bg && prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { if (retry > 0) retval = EX_BG; return retval; } /* create mount deamon client */ /* See if the nfs host = mount host. */ if (mounthost) { if (mounthost[0] >= '0' && mounthost[0] <= '9') { mount_server_addr.sin_family = AF_INET; mount_server_addr.sin_addr.s_addr = inet_addr(hostname); } else {#ifdef NO_GETHOSTBYNAME fprintf(stderr, "ERROR (%d): no gethostbyname()\n", __LINE__);#else if ((hp = gethostbyname(mounthost)) == 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); } mount_server_addr.sin_family = AF_INET; memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length); }#endif } } /* * The following loop implements the mount retries. On the first * call, "running_bg" is 0. When the mount times out, and the * "bg" option is set, the exit status EX_BG will be returned. * For a backgrounded mount, there will be a second call by the * child process with "running_bg" set to 1. * * The case where the mount point is not present and the "bg" * option is set, is treated as a timeout. This is done to * support nested mounts. * * The "retry" count specified by the user is the number of * minutes to retry before giving up. * * Only the first error message will be displayed. */ retry_timeout.tv_sec = 3; retry_timeout.tv_usec = 0; total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; timeout = time(NULL) + 60 * retry; prevt = 0; t = 30; val = 1; for (;;) { if (bg && stat(node, &statbuf) == -1) { if (running_bg) { sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ val *= 2; if (val > 30) val = 30; } } else { /* be careful not to use too many CPU cycles */ if (t - prevt < 30) sleep(30); pm_mnt = get_mountport(&mount_server_addr, mountprog, mountvers, proto, mountport); /* contact the mount daemon via TCP */ mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; switch (pm_mnt->pm_prot) { case IPPROTO_UDP: mclient = clntudp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, retry_timeout, &msock); if (mclient) break; mount_server_addr.sin_port = htons(pm_mnt->pm_port); msock = RPC_ANYSOCK; case IPPROTO_TCP: mclient = clnttcp_create(&mount_server_addr, pm_mnt->pm_prog, pm_mnt->pm_vers, &msock, 0, 0); break; default: mclient = 0; } if (mclient) { /* try to mount hostname:dirname */ mclient->cl_auth = authunix_create_default(); /* make pointers in xdr_mountres3 NULL so * that xdr_array allocates memory for us */ memset(&status, 0, sizeof(status)); if (pm_mnt->pm_vers == 3) clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &dirname, (xdrproc_t) xdr_mountres3, (caddr_t) &status, total_timeout); else clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, (caddr_t) &dirname, (xdrproc_t) xdr_fhstatus, (caddr_t) &status, total_timeout); if (clnt_stat == RPC_SUCCESS) break; /* we're done */ if (errno != ECONNREFUSED) { clnt_perror(mclient, "mount"); goto fail; /* don't retry */ } if (!running_bg && prevt == 0) clnt_perror(mclient, "mount"); auth_destroy(mclient->cl_auth); clnt_destroy(mclient); mclient = 0; close(msock); } else { if (!running_bg && prevt == 0) clnt_pcreateerror("mount"); } prevt = t; } if (!bg) goto fail; if (!running_bg) { prev_bg_host = xstrdup(hostname); if (retry > 0) retval = EX_BG; goto fail; } t = time(NULL); if (t >= timeout) goto fail; } nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; if (nfsvers == 2) { if (status.nfsv2.fhs_status != 0) { error_msg("%s:%s failed, reason given by server: %s", hostname, dirname, nfs_strerror(status.nfsv2.fhs_status)); goto fail; } memcpy(data.root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE);#if NFS_MOUNT_VERSION >= 4 data.root.size = NFS_FHSIZE; memcpy(data.old_root.data, (char *) status.nfsv2.fhstatus_u.fhs_fhandle, NFS_FHSIZE);#endif } else {#if NFS_MOUNT_VERSION >= 4 fhandle3 *my_fhandle; if (status.nfsv3.fhs_status != 0) { error_msg("%s:%s failed, reason given by server: %s", hostname, dirname, nfs_strerror(status.nfsv3.fhs_status)); goto fail; } my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; memset(data.old_root.data, 0, NFS_FHSIZE); memset(&data.root, 0, sizeof(data.root)); data.root.size = my_fhandle->fhandle3_len; memcpy(data.root.data, (char *) my_fhandle->fhandle3_val, my_fhandle->fhandle3_len); data.flags |= NFS_MOUNT_VER3;#endif } /* create nfs socket for kernel */ if (tcp) { if (nfs_mount_version < 3) { printf(_("NFS over TCP is not supported.\n")); goto fail; } fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { perror(_("nfs socket")); goto fail; } if (bindresvport(fsock, 0) < 0) { perror(_("nfs bindresvport")); goto fail; } if (port == 0) { server_addr.sin_port = PMAPPORT; port = pmap_getport(&server_addr, nfsprog, nfsvers, tcp ? IPPROTO_TCP : IPPROTO_UDP); if (port == 0) port = NFS_PORT;#ifdef NFS_MOUNT_DEBUG else printf(_("used portmapper to find NFS port\n"));#endif }#ifdef NFS_MOUNT_DEBUG printf(_("using port %d for nfs deamon\n"), port);#endif server_addr.sin_port = htons(port); /* * connect() the socket for kernels 1.3.10 and below only, * to avoid problems with multihomed hosts. * --Swen */ if (get_kernel_revision() <= 66314 && connect(fsock, (struct sockaddr *) &server_addr, sizeof (server_addr)) < 0) { perror(_("nfs connect")); goto fail; } /* prepare data structure for kernel */ data.fd = fsock; memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); strncpy(data.hostname, hostname, sizeof(data.hostname)); /* clean up */ auth_destroy(mclient->cl_auth); clnt_destroy(mclient); close(msock); return 0; /* abort */fail: if (msock != -1) { if (mclient) { auth_destroy(mclient->cl_auth); clnt_destroy(mclient); } close(msock); } if (fsock != -1) close(fsock); return retval;} /* * We need to translate between nfs status return values and * the local errno values which may not be the same. * * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno: * "after #include <errno.h> the symbol errno is reserved for any use, * it cannot even be used as a struct tag or field name". */#ifndef EDQUOT#define EDQUOT ENOSPC#endifstatic struct { enum nfs_stat stat; int errnum;} nfs_errtbl[] = { { NFS_OK, 0 }, { NFSERR_PERM, EPERM }, { NFSERR_NOENT, ENOENT }, { NFSERR_IO, EIO }, { NFSERR_NXIO, ENXIO }, { NFSERR_ACCES, EACCES }, { NFSERR_EXIST, EEXIST }, { NFSERR_NODEV, ENODEV }, { NFSERR_NOTDIR, ENOTDIR }, { NFSERR_ISDIR, EISDIR },#ifdef NFSERR_INVAL { NFSERR_INVAL, EINVAL }, /* that Sun forgot */#endif { NFSERR_FBIG, EFBIG }, { NFSERR_NOSPC, ENOSPC }, { NFSERR_ROFS, EROFS }, { NFSERR_NAMETOOLONG, ENAMETOOLONG }, { NFSERR_NOTEMPTY, ENOTEMPTY }, { NFSERR_DQUOT, EDQUOT }, { NFSERR_STALE, ESTALE },#ifdef EWFLUSH { NFSERR_WFLUSH, EWFLUSH },#endif /* Throw in some NFSv3 values for even more fun (HP returns these) */ { 71, EREMOTE }, { -1, EIO }};static char *nfs_strerror(int status){ int i; static char buf[256]; for (i = 0; nfs_errtbl[i].stat != -1; i++) { if (nfs_errtbl[i].stat == status) return strerror(nfs_errtbl[i].errnum); } sprintf(buf, _("unknown nfs status return value: %d"), status); return buf;}static bool_txdr_fhandle (XDR *xdrs, fhandle objp){ //register int32_t *buf; if (!xdr_opaque (xdrs, objp, FHSIZE)) return FALSE; return TRUE;}bool_txdr_fhstatus (XDR *xdrs, fhstatus *objp){ //register int32_t *buf; if (!xdr_u_int (xdrs, &objp->fhs_status)) return FALSE; switch (objp->fhs_status) { case 0: if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) return FALSE; break; default: break; } return TRUE;}bool_txdr_dirpath (XDR *xdrs, dirpath *objp){ //register int32_t *buf; if (!xdr_string (xdrs, objp, MNTPATHLEN)) return FALSE; return TRUE;}bool_txdr_fhandle3 (XDR *xdrs, fhandle3 *objp){ //register int32_t *buf; if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) return FALSE; return TRUE;}#ifdef TOOL_CHAIN/* * XDR integers */bool_t_xdr_int(xdrs, ip) XDR *xdrs; int *ip;{#ifdef lint (void) (xdr_short(xdrs, (short *)ip)); return (xdr_long(xdrs, (long *)ip));#else if (sizeof (int) == sizeof (long)) { return (xdr_long(xdrs, (long *)ip)); } else { return (xdr_short(xdrs, (short *)ip)); }#endif}#endif /* TOOL_CHAIN */bool_txdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp){ //register int32_t *buf; if (!xdr_fhandle3 (xdrs, &objp->fhandle)) return FALSE; if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0, sizeof (int), (xdrproc_t) _xdr_int)) /* xdr_int --> _xdr_int */ return FALSE; return TRUE;}bool_txdr_mountstat3 (XDR *xdrs, mountstat3 *objp){ //register int32_t *buf; if (!xdr_enum (xdrs, (enum_t *) objp)) return FALSE; return TRUE;}bool_txdr_mountres3 (XDR *xdrs, mountres3 *objp){ //register int32_t *buf; if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) return FALSE; switch (objp->fhs_status) { case MNT_OK: if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) return FALSE; break; default: break; } return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -