X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmountd%2Fmountd.c;h=8f6f9cb9d85d8ad69754a9db1bdbda2233feab76;hp=9f467d1f9b4c4e227a91a87bb15b691c561199f1;hb=b01c85ea978f15d313961724d9a64c8ae18b3766;hpb=8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9 diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c index 9f467d1..8f6f9cb 100644 --- a/utils/mountd/mountd.c +++ b/utils/mountd/mountd.c @@ -14,21 +14,32 @@ #include #include #include +#include #include #include #include +#include #include "xmalloc.h" #include "misc.h" #include "mountd.h" #include "rpcmisc.h" +extern void cache_open(void); +extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p); +extern void cache_export(nfs_export *exp); + +extern void my_svc_run(void); + static void usage(const char *, int exitcode); static exports get_exportlist(void); -static struct knfs_fh * get_rootfh(struct svc_req *, dirpath *, int *); +static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, int *, int v3); + +int new_cache = 0; static struct option longopts[] = { { "foreground", 0, 0, 'F' }, + { "descriptors", 1, 0, 'o' }, { "debug", 1, 0, 'd' }, { "help", 0, 0, 'h' }, { "exports-file", 1, 0, 'f' }, @@ -36,6 +47,7 @@ static struct option longopts[] = { "no-nfs-version", 1, 0, 'N' }, { "version", 0, 0, 'v' }, { "port", 1, 0, 'p' }, + { "no-tcp", 0, 0, 'n' }, { NULL, 0, 0, 0 } }; @@ -65,19 +77,21 @@ mount_null_1_svc(struct svc_req *rqstp, void *argp, void *resp) bool_t mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res) { - struct knfs_fh *fh; + struct nfs_fh_len *fh; xlog(D_CALL, "MNT1(%s) called", *path); - if ((fh = get_rootfh(rqstp, path, &res->fhs_status)) != NULL) - memcpy(&res->fhstatus_u.fhs_fhandle, fh, 32); + if ((fh = get_rootfh(rqstp, path, &res->fhs_status, 0)) != NULL) + memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32); return 1; } bool_t mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res) { + struct sockaddr_in *addr = + (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); xlog(L_NOTICE, "dump request from %s", - inet_ntoa(svc_getcaller(rqstp->rq_xprt)->sin_addr)); + inet_ntoa(addr->sin_addr)); *res = mountlist_list(); return 1; @@ -86,7 +100,8 @@ mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res) bool_t mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) { - struct sockaddr_in *sin = svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *sin + = (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); nfs_export *exp; char *p = *argp; char rpath[MAXPATHLEN+1]; @@ -102,8 +117,14 @@ mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) if (!(exp = auth_authenticate("unmount", sin, p))) { return 1; } - mountlist_del(exp, p); - export_reset (exp); + if (new_cache) { + if (strcmp(inet_ntoa(exp->m_client->m_addrlist[0]), exp->m_client->m_hostname)) + mountlist_del(inet_ntoa(exp->m_client->m_addrlist[0]), exp->m_client->m_hostname); + mountlist_del(exp->m_client->m_hostname, p); + } else { + mountlist_del(exp->m_client->m_hostname, p); + export_reset (exp); + } return 1; } @@ -113,15 +134,17 @@ mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp) /* Reload /etc/xtab if necessary */ auth_reload(); - mountlist_del_all(svc_getcaller(rqstp->rq_xprt)); + mountlist_del_all((struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt)); return 1; } bool_t mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp) { + struct sockaddr_in *addr = + (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); xlog(L_NOTICE, "export request from %s", - inet_ntoa(svc_getcaller(rqstp->rq_xprt)->sin_addr)); + inet_ntoa(addr->sin_addr)); *resp = get_exportlist(); return 1; } @@ -129,8 +152,10 @@ mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp) bool_t mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) { + struct sockaddr_in *addr = + (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); xlog(L_NOTICE, "exportall request from %s", - inet_ntoa(svc_getcaller(rqstp->rq_xprt)->sin_addr)); + inet_ntoa(addr->sin_addr)); *resp = get_exportlist(); return 1; } @@ -149,7 +174,8 @@ mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) bool_t mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) { - struct sockaddr_in *sin = svc_getcaller(rqstp->rq_xprt); + struct sockaddr_in *sin + = (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); struct stat stb; nfs_export *exp; char rpath[MAXPATHLEN+1]; @@ -170,7 +196,7 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) } /* Now authenticate the intruder... */ - if (!(exp = auth_authenticate("mount", sin, p))) { + if (!(exp = auth_authenticate("pathconf", sin, p))) { return 1; } else if (stat(p, &stb) < 0) { xlog(L_WARNING, "can't stat exported dir %s: %s", @@ -203,25 +229,26 @@ bool_t mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res) { static int flavors[] = { AUTH_NULL, AUTH_UNIX }; - struct knfs_fh *fh; + struct nfs_fh_len *fh; xlog(D_CALL, "MNT3(%s) called", *path); - if ((fh = get_rootfh(rqstp, path, (int *) &res->fhs_status)) != NULL) { + if ((fh = get_rootfh(rqstp, path, (int *) &res->fhs_status, 1)) != NULL) { struct mountres3_ok *ok = &res->mountres3_u.mountinfo; - ok->fhandle.fhandle3_len = 32; - ok->fhandle.fhandle3_val = (char *) fh; + ok->fhandle.fhandle3_len = fh->fh_size; + ok->fhandle.fhandle3_val = fh->fh_handle; ok->auth_flavors.auth_flavors_len = 2; ok->auth_flavors.auth_flavors_val = flavors; } return 1; } -static struct knfs_fh * -get_rootfh(struct svc_req *rqstp, dirpath *path, int *error) +static struct nfs_fh_len * +get_rootfh(struct svc_req *rqstp, dirpath *path, int *error, int v3) { - struct sockaddr_in *sin = svc_getcaller(rqstp->rq_xprt); - struct stat stb; + struct sockaddr_in *sin = + (struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt); + struct stat stb, estb; nfs_export *exp; char rpath[MAXPATHLEN+1]; char *p = *path; @@ -251,22 +278,57 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, int *error) } else if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { xlog(L_WARNING, "%s is not a directory or regular file", p); *error = NFSERR_NOTDIR; + } else if (stat(exp->m_export.e_path, &estb) < 0) { + xlog(L_WARNING, "can't stat export point %s: %s", + p, strerror(errno)); + *error = NFSERR_NOENT; + } else if (estb.st_dev != stb.st_dev + /* && (!new_cache || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) */ + ) { + xlog(L_WARNING, "request to export directory %s below nearest filesystem %s", + p, exp->m_export.e_path); + *error = NFSERR_ACCES; + } else if (exp->m_export.e_mountpoint && + !is_mountpoint(exp->m_export.e_mountpoint[0]? + exp->m_export.e_mountpoint: + exp->m_export.e_path)) { + xlog(L_WARNING, "request to export an unmounted filesystem: %s", + p); + *error = NFSERR_NOENT; + } else if (new_cache) { + /* This will be a static private nfs_export with just one + * address. We feed it to kernel then extract the filehandle, + * + */ + struct nfs_fh_len *fh; + + cache_export(exp); + fh = cache_get_filehandle(exp, v3?64:32, p); + if (fh == NULL) + *error = NFSERR_ACCES; + else + *error = NFS_OK; + return fh; } else { - struct knfs_fh *fh; + struct nfs_fh_len *fh; - if (!exp->m_exported) + if (exp->m_exported<1) export_export(exp); if (!exp->m_xtabent) xtab_append(exp); - /* We first try the new nfs syscall. */ - fh = getfh ((struct sockaddr *) sin, p); - if (fh == NULL && errno == EINVAL) - /* Let's try the old one. */ - fh = getfh_old ((struct sockaddr *) sin, - stb.st_dev, stb.st_ino); + if (v3) + fh = getfh_size ((struct sockaddr *) sin, p, 64); + if (!v3 || (fh == NULL && errno == EINVAL)) { + /* We first try the new nfs syscall. */ + fh = getfh ((struct sockaddr *) sin, p); + if (fh == NULL && errno == EINVAL) + /* Let's try the old one. */ + fh = getfh_old ((struct sockaddr *) sin, + stb.st_dev, stb.st_ino); + } if (fh != NULL) { - mountlist_add(exp, p); + mountlist_add(exp->m_client->m_hostname, p); *error = NFS_OK; export_reset (exp); return fh; @@ -312,7 +374,7 @@ get_exportlist(void) e = (struct exportnode *) xmalloc(sizeof(*e)); e->ex_next = elist; e->ex_groups = NULL; - e->ex_dir = strdup(exp->m_export.m_path); + e->ex_dir = xstrdup(exp->m_export.m_path); elist = e; } @@ -375,13 +437,23 @@ main(int argc, char **argv) char *export_file = _PATH_EXPORTS; int foreground = 0; int port = 0; + int descriptors = 0; int c; struct sigaction sa; + struct rlimit rlim; /* Parse the command line options and arguments. */ opterr = 0; - while ((c = getopt_long(argc, argv, "Fd:f:p:P:hN:V:v", longopts, NULL)) != EOF) + while ((c = getopt_long(argc, argv, "o:n:Fd:f:p:P:hN:V:v", longopts, NULL)) != EOF) switch (c) { + case 'o': + descriptors = atoi(optarg); + if (descriptors <= 0) { + fprintf(stderr, "%s: bad descriptors: %s\n", + argv [0], optarg); + usage(argv [0], 1); + } + break; case 'F': foreground = 1; break; @@ -406,6 +478,9 @@ main(int argc, char **argv) case 'N': nfs_version &= ~(1 << (atoi (optarg) - 1)); break; + case 'n': + _rpcfdtype = SOCK_DGRAM; + break; case 'V': nfs_version |= 1 << (atoi (optarg) - 1); break; @@ -423,8 +498,31 @@ main(int argc, char **argv) if (optind != argc || !(nfs_version & 0x7)) usage(argv [0], 1); + if (chdir(NFS_STATEDIR)) { + fprintf(stderr, "%s: chdir(%s) failed: %s\n", + argv [0], NFS_STATEDIR, strerror(errno)); + exit(1); + } + + if (getrlimit (RLIMIT_NOFILE, &rlim) != 0) + fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n", + argv [0], strerror(errno)); + else { + /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */ + if ((descriptors == 0 && rlim.rlim_cur > FD_SETSIZE) || + descriptors > FD_SETSIZE) + descriptors = FD_SETSIZE; + if (descriptors) { + rlim.rlim_cur = descriptors; + if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) { + fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n", + argv [0], strerror(errno)); + exit(1); + } + } + } /* Initialize logging. */ - xlog_open("mountd"); +/* xlog_open("mountd"); */ sa.sa_handler = SIG_IGN; sa.sa_flags = 0; @@ -432,16 +530,30 @@ main(int argc, char **argv) sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + /* WARNING: the following works on Linux and SysV, but not BSD! */ + sigaction(SIGCHLD, &sa, NULL); + + /* Daemons should close all extra filehandles ... *before* RPC init. */ + if (!foreground) { + int fd = sysconf (_SC_OPEN_MAX); + while (--fd > 2) + (void) close(fd); + } + + new_cache = check_new_cache(); + if (new_cache) + cache_open(); if (nfs_version & 0x1) rpc_init("mountd", MOUNTPROG, MOUNTVERS, - mount_dispatch, port, 0); + mount_dispatch, port); if (nfs_version & (0x1 << 1)) rpc_init("mountd", MOUNTPROG, MOUNTVERS_POSIX, - mount_dispatch, port, 0); + mount_dispatch, port); if (nfs_version & (0x1 << 2)) rpc_init("mountd", MOUNTPROG, MOUNTVERS_NFSV3, - mount_dispatch, port, 0); + mount_dispatch, port); sa.sa_handler = killer; sigaction(SIGHUP, &sa, NULL); @@ -471,7 +583,7 @@ main(int argc, char **argv) xlog_background(); } - svc_run(); + my_svc_run(); xlog(L_ERROR, "Ack! Gack! svc_run returned!\n"); exit(1); @@ -481,9 +593,9 @@ static void usage(const char *prog, int n) { fprintf(stderr, -"Usage: %s [-Fhnv] [-d kind] [-f exports-file] [-V version]\n" -" [-N version] [--debug kind] [-p|--port port] [--help] [--version]\n" -" [--exports-file=file] [--nfs-version version]\n" -" [--no-nfs-version version]\n", prog); +"Usage: %s [-F|--foreground] [-h|--help] [-v|--version] [-d kind|--debug kind]\n" +" [-o num|--descriptors num] [-f exports-file|--exports-file=file]\n" +" [-p|--port port] [-V version|--nfs-version version]\n" +" [-N version|--no-nfs-version version] [-n|--no-tcp]\n", prog); exit(n); }