home *** CD-ROM | disk | FTP | other *** search
- /*
- * nfsd This program handles RPC "NFS" data requests.
- *
- * Usage: [rpc.]nfsd [-dhnprv] [-f authfile]
- *
- * Authors: Mark A. Shand, May 1988
- * Donald J. Becker, <becker@super.org>
- * Rick Sladkey, <jrs@world.std.com>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Eric Kasten, <tigger@tigger.cl.msu.edu>
- *
- * Copyright 1988 Mark A. Shand
- * This software maybe be used for any purpose provided
- * the above copyright notice is retained. It is supplied
- * as is, with no warranty expressed or implied.
- */
-
- #include "nfsd.h"
- #include "getopt.h"
- #include "fsusage.h"
-
- #define _RPCSVC_CLOSEDOWN 120
-
- static char iobuf[NFS_MAXDATA];
- static char pathbuf[NFS_MAXPATHLEN + 1];
- static char pathbuf_1[NFS_MAXPATHLEN + 1];
- int _rpcpmstart = 0;
- int _rpcsvcdirty = 0;
- int _rpcfdtype = 0;
-
- static _PRO(void usage, (FILE *, int));
-
- extern char version[];
- static char *program_name;
- static struct option longopts[] =
- {
- { "debug", 0, 0, 'd' },
- { "exports-file", 1, 0, 'f' },
- { "help", 0, 0, 'h' },
- { "allow-non-root", 0, 0, 'n' },
- { "promiscuous", 0, 0, 'p' },
- { "re-export", 0, 0, 'r', },
- { "version", 0, 0, 'v' },
- { NULL, 0, 0, 0 }
- };
-
- extern clnt_param *cp; /* only for the option list */
-
- extern _PRO(void nfs_dispatch, (struct svc_req * rqstp, SVCXPRT * transp));
- static _PRO(nfsstat build_path, (char *buf, diropargs * da));
- static _PRO(int makesock, (int port, int proto, int socksz));
- static _PRO(void closedown, (int sig));
-
- extern void xdr_free(); /* fill this in later */
- extern void pmap_unset(); /* why here??? */
-
- /*
- * check_ro_attrib -- tig
- *
- * This function will check to see if the nfs directory is mounted
- * read only. If it is an error status is returned.
- *
- * Parameters:
- * int auth - Where fs authentication is expected.
- * struct svc_req *rqstp - The RPC service request.
- * char *path - The file system path.
- * clnt_param *cp - The Client fs parameters as supplied from the
- * internal table of exported file systems.
- *
- * Returns:
- * NFS_OK - If authenication isn't needed or if fs is read/write.
- * NFSERR_ACCES - If the fs can't be found among the exported fs.
- * NFSERR_ROFS - If the fs is a read-only fs.
- */
- static inline int check_ro_attrib(auth, rqstp, path, cp)
- int auth;
- struct svc_req *rqstp;
- char *path;
- clnt_param *cp;
- {
- /* Now we attempt to authenticate the clients credentials. */
- if (auth) {
- /* Retrieve the client's parameters. */
- if ((cp = auth_clnt(rqstp, path)) == NULL)
- return (NFSERR_ACCES);
- /* If this is a read only mount, then we'd better punt. */
- if (cp->o.read_only)
- return (NFSERR_ROFS);
- }
- return (NFS_OK);
- }
-
- static inline nfsstat build_path(buf, da)
- char *buf;
- diropargs *da;
- {
- nfsstat status;
- char *path, *fname;
-
- if ((path = fh_path(&(da->dir), &status)) == 0)
- return (NFSERR_STALE);
-
- while (*path) /* strcpy(buf, path); */
- *buf++ = *path++;
- *buf++ = '/'; /* strcat(buf, "/"); */
- fname = da->name;
- while (*fname) /* strcat(pathbuf, argp->where.name); */
- *buf++ = *fname++;
- *buf = '\0';
- return (NFS_OK);
- }
-
- /*
- * The "wrappers" of the following functions came from `rpcgen -l nfs_prot.x`.
- * This normally generates the client routines, but it provides nice
- * prototypes for the server routines also.
- */
- #define CLIENT struct svc_req
-
- int nfsd_nfsproc_null_2(argp)
- void *argp;
- {
- return (0);
- }
-
- int nfsd_nfsproc_getattr_2(argp)
- nfs_fh *argp;
- {
- return (getattr(argp, &result.attrstat.attrstat_u.attributes, NULL));
- }
-
- int nfsd_nfsproc_setattr_2(argp)
- sattrargs *argp;
- {
- nfsstat status;
- char *path;
- struct stat buf;
-
- if ((path = fh_path(&(argp->file), &status)) == NULL) {
- /* That means we can't get a path to the file. Give up. */
- return (NFSERR_STALE);
- }
- status = check_ro_attrib(client_authenticate, svc_rqstp, path, cp);
- if (status != NFS_OK)
- return(status);
-
- errno = 0;
- /* Stat the file first and only change fields that are different. */
- if (lstat(path, &buf) < 0)
- goto failure;
- if (((argp->attributes.uid != -1
- && argp->attributes.uid != buf.st_uid)
- || (argp->attributes.gid != -1
- && argp->attributes.gid != buf.st_gid))
- && lchown(path, argp->attributes.uid, argp->attributes.gid) < 0)
- goto failure;
- if (argp->attributes.mode != -1
- && (argp->attributes.mode & 07777) != (buf.st_mode & 07777)
- && chmod(path, argp->attributes.mode) < 0)
- goto failure;
- if (S_ISREG(buf.st_mode)
- && argp->attributes.size != -1
- && argp->attributes.size != buf.st_size
- && truncate(path, argp->attributes.size) < 0)
- goto failure;
- if ((argp->attributes.atime.seconds != (unsigned) -1
- && argp->attributes.atime.seconds != buf.st_atime)
- || (argp->attributes.mtime.seconds != (unsigned) -1
- && argp->attributes.mtime.seconds != buf.st_mtime)) {
- struct timeval tvp[2];
- tvp[0].tv_sec = argp->attributes.atime.seconds;
- tvp[0].tv_usec = argp->attributes.atime.useconds;
- tvp[1].tv_sec = argp->attributes.mtime.seconds;
- tvp[1].tv_usec = argp->attributes.mtime.useconds;
- if (utimes(path, tvp) < 0)
- goto failure;
- }
- return (getattr(&(argp->file),
- &(result.attrstat.attrstat_u.attributes), NULL));
-
- failure:
- return (nfs_errno());
- }
-
- int nfsd_nfsproc_root_2(argp)
- void *argp;
- {
- return (0);
- }
-
- int nfsd_nfsproc_lookup_2(argp)
- diropargs *argp;
- {
- int status;
- struct stat sbuf;
- struct stat *sbp = &sbuf;
- diropokres *dp = &result.diropres.diropres_u.diropres;
-
- status = fh_compose(argp, &(dp->file), &sbp, -1, -1);
- if (status == NFS_OK) {
- status = getattr(&(dp->file), &(dp->attributes), sbp);
- if (status == NFS_OK)
- dprintf(1, "\tnew_fh = %s\n", fh_pr(&(dp->file)));
- }
- return (status);
- }
-
- int nfsd_nfsproc_readlink_2(argp)
- nfs_fh *argp;
- {
- nfsstat status;
- char *path;
- int cc;
-
- if ((path = fh_path(argp, &status)) == 0)
- return (NFSERR_STALE);
-
- errno = 0;
- if ((cc = readlink(path, pathbuf, NFS_MAXPATHLEN)) < 0) {
- dprintf(1, " >>> %s\n", strerror(errno));
- return (nfs_errno());
- }
- status = NFS_OK;
- pathbuf[cc] = '\0'; /* readlink() doesn't null terminate!! */
- result.readlinkres.readlinkres_u.data = pathbuf;
-
- /* Now we attempt to authenticate the clients credentials. */
- if ((cp = auth_clnt(svc_rqstp, path)) == NULL)
- return (NFSERR_ACCES);
-
- if (cp->o.link_relative && pathbuf[0] == '/') {
- /*
- * We've got an absolute (locally) pathname, and we should
- * translate to a relative pathname for the client. We do
- * this by prepending the correct number of "../"es to the
- * path. This cannot work if the client does not mount the
- * specified subtree of the filesystem.
- */
- int slash_cnt = 0;
- char *p, *q;
-
- /* Count how many directories down we are. */
- for (p = path + 1; *p != '\0'; p++)
- if (*p == '/')
- slash_cnt++;
-
- /*
- * Ok, now we are finished with the orginal file `path'
- * and will only deal with the link target.
- */
- p = &pathbuf[cc]; /* Point to the end and calculate */
- if (slash_cnt == 0)
- q = p + 1; /* the extra space take by a */
- else /* prepended '.' */
- q = p + 3 * slash_cnt - 1; /* or '../.../..' */
-
- if (q >= pathbuf + NFS_MAXPATHLEN) {
- dprintf(1, " [[NAME TOO LONG!!]]\n");
- return (NFSERR_NAMETOOLONG);
- } else {
- /* Add some space at the beginning of the string. */
- while (p >= pathbuf)
- *q-- = *p--;
-
- if (slash_cnt == 0)
- pathbuf[0] = '.';
- else {
- /*
- * This overwrites the leading '/' on the
- * last iteration.
- */
- for (p = pathbuf; slash_cnt > 0; slash_cnt--) {
- *p++ = '.';
- *p++ = '.';
- *p++ = '/';
- }
- }
- }
- }
- dprintf(1, " %s\n", result.readlinkres.readlinkres_u.data);
- return (NFS_OK);
- }
-
- int nfsd_nfsproc_read_2(argp)
- readargs *argp;
- {
- nfsstat status;
- int fd;
-
- if ((fd = fh_fd(&(argp->file), &status, O_RDONLY)) < 0) {
- return ((int) status);
- }
- errno = 0;
- (void) lseek(fd, (long) argp->offset, L_SET);
- result.readres.readres_u.reply.data.data_val = iobuf;
- if (!errno)
- result.readres.readres_u.reply.data.data_len =
- read(fd, iobuf, argp->count);
- fd_inactive(fd);
- if (errno)
- return (nfs_errno());
- return (getattr(&(argp->file),
- &(result.readres.readres_u.reply.attributes), NULL));
- }
-
- int nfsd_nfsproc_writecache_2(argp)
- void *argp;
- {
- return (0);
- }
-
- int nfsd_nfsproc_write_2(argp)
- writeargs *argp;
- {
- nfsstat status;
- int fd;
-
- if ((fd = fh_fd(&(argp->file), &status, O_WRONLY)) < 0) {
- return ((int) status);
- }
- errno = 0;
- (void) lseek(fd, (long) argp->offset, L_SET);
- if (errno == 0) { /* We should never fail. */
- if (write(fd, argp->data.data_val, argp->data.data_len) !=
- argp->data.data_len) {
- dprintf(1, " Write failure, errno is %d.\n", errno);
- }
- }
- fd_inactive(fd);
- if (errno)
- return (nfs_errno());
- return (getattr(&(argp->file),
- &(result.attrstat.attrstat_u.attributes), NULL));
- }
-
- #define CREATE_OMODE O_RDWR
-
- int nfsd_nfsproc_create_2(argp)
- createargs *argp;
- {
- nfsstat status;
- int tmpfd, flags;
- struct stat sbuf;
- struct stat *sbp = &sbuf;
- uid_t target_uid;
- gid_t target_gid;
- int is_borc;
- int dev;
- int exists;
-
- status = build_path(pathbuf, &argp->where);
- if (status != NFS_OK)
- return ((int) status);
- dprintf(1, "\tfullpath='%s'\n", pathbuf);
- errno = 0;
-
- exists = lstat(pathbuf, &sbuf) == 0;
-
- /* Compensate for a really bizarre bug in SunOS derived clients. */
- if ((argp->attributes.mode & S_IFMT) == 0)
- argp->attributes.mode |= exists
- ? (sbuf.st_mode & S_IFMT) : S_IFREG;
-
- /* First handle any unusual file-types. */
- if (!S_ISREG(argp->attributes.mode)) {
- if (S_ISBLK(argp->attributes.mode)
- || S_ISCHR(argp->attributes.mode)) {
- is_borc = 1;
- /* This is probably better than just using
- the size field by itself, but not by much. */
- dev = makedev(((argp->attributes.size >> 8) & 0xff),
- (argp->attributes.size & 0xff));
- }
- else {
- is_borc = 0;
- dev = 0;
- }
- /* mknod will fail for EEXIST, we'll let it succeed. */
- if (exists) {
- /* But make sure it's the same kind of special file. */
- if ((argp->attributes.mode & S_IFMT)
- != (sbuf.st_mode & S_IFMT))
- return (NFSERR_EXIST);
- /* And that the major and minor numbers agree. */
- if (is_borc && dev != sbuf.st_rdev)
- return (NFSERR_EXIST);
- }
- else {
- status = check_ro_attrib(client_authenticate,
- svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
- if (mknod(pathbuf, argp->attributes.mode, dev) < 0)
- return (nfs_errno());
- if (stat(pathbuf, &sbuf) < 0)
- return (nfs_errno());
- }
- tmpfd = -1;
- }
- else {
- status = check_ro_attrib(client_authenticate,
- svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
- flags = (argp->attributes.size == 0 ?
- CREATE_OMODE | O_CREAT | O_TRUNC :
- CREATE_OMODE | O_CREAT);
- tmpfd = path_open(pathbuf, flags, argp->attributes.mode);
- if (tmpfd < 0)
- goto failure;
- (void) fstat(tmpfd, &sbuf);
- }
-
- target_uid = argp->attributes.uid;
- target_gid = argp->attributes.gid;
-
- if ((target_uid != (uid_t) -1 && sbuf.st_uid != target_uid) ||
- (target_gid != (gid_t) -1 && sbuf.st_gid != target_gid)) {
- if (lchown(pathbuf, target_uid, target_gid) < 0)
- goto failure;
- if (target_uid != (uid_t) -1)
- sbuf.st_uid = target_uid;
- if (target_gid != (gid_t) -1)
- sbuf.st_gid = target_gid;
- }
-
- if (S_ISREG(argp->attributes.mode)
- && argp->attributes.size != -1
- && argp->attributes.size != sbuf.st_size) {
- if (truncate(pathbuf, argp->attributes.size) < 0)
- goto failure;
- sbuf.st_size = argp->attributes.size;
- }
- if ((argp->attributes.atime.seconds != -1 &&
- argp->attributes.atime.seconds != sbuf.st_atime) ||
- (argp->attributes.mtime.seconds != -1 &&
- argp->attributes.mtime.seconds != sbuf.st_mtime)) {
- struct timeval tvp[2];
- tvp[0].tv_sec = argp->attributes.atime.seconds;
- tvp[0].tv_usec = argp->attributes.atime.useconds;
- tvp[1].tv_sec = argp->attributes.mtime.seconds;
- tvp[1].tv_usec = argp->attributes.mtime.useconds;
- if (utimes(pathbuf, tvp) < 0)
- goto failure;
- if (argp->attributes.atime.seconds != -1)
- sbuf.st_atime = argp->attributes.atime.seconds;
- if (argp->attributes.mtime.seconds != -1)
- sbuf.st_mtime = argp->attributes.mtime.seconds;
- }
- if (argp->attributes.mode != -1
- && (argp->attributes.mode & 07777) != (sbuf.st_mode & 07777)) {
- if (chmod(pathbuf, argp->attributes.mode) < 0)
- goto failure;
- sbuf.st_mode = (sbuf.st_mode & S_IFMT)
- | (argp->attributes.mode & 07777);
- }
- status = fh_compose(&(argp->where),
- &(result.diropres.diropres_u.diropres.file), &sbp,
- tmpfd, CREATE_OMODE);
- if (status != NFS_OK)
- goto failure;
- status = getattr(&(result.diropres.diropres_u.diropres.file),
- &(result.diropres.diropres_u.diropres.attributes),
- sbp);
- if (status != NFS_OK)
- goto failure;
- dprintf(1, "\tnew_fh = %s\n",
- fh_pr(&(result.diropres.diropres_u.diropres.file)));
- return (status);
-
- failure:
- dprintf(1, "\tcreate failed -- errno returned=%d.\n", errno);
- if (tmpfd != -1)
- close(tmpfd);
- return (nfs_errno());
- }
-
- #undef CREATE_OMODE
-
- int nfsd_nfsproc_remove_2(argp)
- diropargs *argp;
- {
- nfsstat status;
-
- status = build_path(pathbuf, argp);
- if (status != NFS_OK)
- return ((int) status);
-
- dprintf(1, "\tfullpath='%s'\n", pathbuf);
-
- status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
-
- /* Remove the file handle from our cache. */
- fh_remove(pathbuf);
-
- if (unlink(pathbuf) != 0)
- return (nfs_errno());
- else
- return (NFS_OK);
- }
-
- int nfsd_nfsproc_rename_2(argp)
- renameargs *argp;
- {
- nfsstat status;
-
- status = build_path(pathbuf, &argp->from);
- if (status != NFS_OK)
- return ((int) status);
- status = build_path(pathbuf_1, &argp->to);
- if (status != NFS_OK)
- return ((int) status);
-
- dprintf(1, "\tpathfrom='%s' pathto='%s'\n", pathbuf, pathbuf_1);
-
- status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
-
- /* Remove any file handle from our cache. */
- fh_remove(pathbuf);
- fh_remove(pathbuf_1);
-
- if (rename(pathbuf, pathbuf_1) != 0)
- return (nfs_errno());
-
- return (NFS_OK);
- }
-
- int nfsd_nfsproc_link_2(argp)
- linkargs *argp;
- {
- nfsstat status;
- char *path;
-
- if ((path = fh_path(&(argp->from), &status)) == 0)
- return (NFSERR_STALE);
-
- status = build_path(pathbuf_1, &argp->to);
- if (status != NFS_OK)
- return ((int) status);
-
- dprintf(1, "\tpathfrom='%s' pathto='%s'\n", path, pathbuf_1);
-
- status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
-
- if (link(path, pathbuf_1) != 0)
- return (nfs_errno());
- return (NFS_OK);
- }
-
- int nfsd_nfsproc_symlink_2(argp)
- symlinkargs *argp;
- {
- nfsstat status;
-
- status = build_path(pathbuf, &argp->from);
- if (status != NFS_OK)
- return ((int) status);
-
- dprintf(1, "\tstring='%s' filename='%s'\n", argp->to, pathbuf);
-
- status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
-
- /*
- * Ignore the attributes, as the NFS version 2 documentation says
- * "On UNIX servers the attributes are never used...",
- */
- if (symlink(argp->to, pathbuf) != 0)
- return (nfs_errno());
- return (NFS_OK);
- }
-
- int nfsd_nfsproc_mkdir_2(argp)
- createargs *argp;
- {
- nfsstat status;
- struct stat sbuf;
- struct stat *sbp = &sbuf;
-
- status = build_path(pathbuf, &argp->where);
- if (status != NFS_OK)
- return ((int) status);
-
- dprintf(1, "\tfullpath='%s'\n", pathbuf);
-
- status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
-
- if (mkdir(pathbuf, argp->attributes.mode) != 0)
- return (nfs_errno());
- status = fh_compose(&(argp->where),
- &(result.diropres.diropres_u.diropres.file), &sbp,
- -1, -1);
- if (status != NFS_OK)
- return ((int) status);
-
- /*
- * Set up the correct ownership. As with create, almost all mkdir
- * requests from the current Sun implementation fail to include
- * explicit uid/gid pairs for creates, so we have to use info
- * from the request authication (now done during dispatch).
- */
- {
- int target_uid = argp->attributes.uid;
- int target_gid = argp->attributes.gid;
-
- if ((target_uid != -1 && sbuf.st_uid != target_uid) ||
- (target_gid != -1 && sbuf.st_gid != target_gid))
- if (lchown(pathbuf, target_uid, target_gid) != 0)
- return (nfs_errno());
- }
-
- /* Note that the spb buffer is now invalid! */
- status = getattr(&(result.diropres.diropres_u.diropres.file),
- &(result.diropres.diropres_u.diropres.attributes), NULL);
- if (status == NFS_OK)
- dprintf(1, "\tnew_fh = %s\n",
- fh_pr(&(result.diropres.diropres_u.diropres.file)));
- return ((int) status);
- }
-
- int nfsd_nfsproc_rmdir_2(argp)
- diropargs *argp;
- {
- nfsstat status;
-
- status = build_path(pathbuf, argp);
- if (status != NFS_OK)
- return ((int) status);
-
- dprintf(1, "\tfullpath='%s'\n", pathbuf);
-
- status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
- if (status != NFS_OK)
- return (status);
-
- /* Remove that file handle from our cache. */
- fh_remove(pathbuf);
-
- if (rmdir(pathbuf) != 0)
- return (nfs_errno());
-
- return (NFS_OK);
- }
-
- /* More Mark Shand code. */
- static int dpsize(dp)
- struct dirent *dp;
- {
- #define DP_SLOP 16
- #define MAX_E_SIZE sizeof(entry) + NAME_MAX + DP_SLOP
- return (sizeof(entry) + NLENGTH(dp) + DP_SLOP);
- }
-
- int nfsd_nfsproc_readdir_2(argp)
- readdirargs *argp;
- {
- static readdirres oldres;
- entry **e;
- long dloc;
- DIR *dirp;
- struct dirent *dp;
- struct stat sbuf;
- int res_size;
- fhcache *h;
- int hideit;
-
- /* Free the previous result, since it has 'malloc'ed strings. */
- xdr_free(xdr_readdirres, (caddr_t) & oldres);
-
- if ((h = fh_find((svc_fh *) &(argp->dir), 0)) == NULL)
- return (NFSERR_STALE);
- hideit = (!re_export && (h->flags & FHC_NFSMOUNTED));
-
- /* This code is from Mark Shand's version */
- errno = 0;
- if (lstat(h->path, &sbuf) < 0 || !(S_ISDIR(sbuf.st_mode)))
- return (NFSERR_NOTDIR);
- if ((dirp = opendir(h->path)) == NULL)
- return ((errno ? nfs_errno() : NFSERR_NAMETOOLONG));
-
- res_size = 0;
- memcpy(&dloc, argp->cookie, sizeof(dloc));
- if (dloc != 0)
- seekdir(dirp, ntohl(dloc));
- e = &(result.readdirres.readdirres_u.reply.entries);
- while (((res_size + MAX_E_SIZE) < argp->count
- || e == &(result.readdirres.readdirres_u.reply.entries))
- && (dp = readdir(dirp)) != NULL) {
- if (hideit && strcmp(dp->d_name, ".") != 0
- && strcmp(dp->d_name, "..") != 0) {
- dp = NULL;
- break;
- }
- if ((*e = (entry *) malloc(sizeof(entry))) == NULL)
- mallocfailed();
- (*e)->fileid = pseudo_inode(dp->d_ino, sbuf.st_dev);
- if (((*e)->name = malloc(NLENGTH(dp) + 1)) == NULL)
- mallocfailed();
- strcpy((*e)->name, dp->d_name);
- dloc = htonl(telldir(dirp));
- memcpy(((*e)->cookie), &dloc, sizeof(nfscookie));
- e = &((*e)->nextentry);
- res_size += dpsize(dp);
- }
- *e = NULL;
- result.readdirres.readdirres_u.reply.eof = (dp == NULL);
- (void) closedir(dirp);
- oldres = result.readdirres;
- return (result.readdirres.status);
- }
-
- /*
- * Only reports free space correctly for the filesystem that the
- * mount point is on. Actually it will work fine for any file
- * handle (e.g. sub mounts) but the NFS spec calls for root_fh
- * to be used by the client when calling this.
- */
- int nfsd_nfsproc_statfs_2(argp)
- nfs_fh *argp;
- {
- nfsstat status;
- char *path;
- struct fs_usage fs;
-
- if ((path = fh_path(argp, &status)) == NULL)
- return (NFSERR_STALE);
-
- if (get_fs_usage(path, NULL, &fs) < 0)
- return (nfs_errno());
- result.statfsres.status = NFS_OK;
- result.statfsres.statfsres_u.reply.tsize = 8*1024;
- result.statfsres.statfsres_u.reply.bsize = 512;
- result.statfsres.statfsres_u.reply.blocks = fs.fsu_blocks;
- result.statfsres.statfsres_u.reply.bfree = fs.fsu_bfree;
- result.statfsres.statfsres_u.reply.bavail = fs.fsu_bavail;
-
- return (NFS_OK);
- }
-
- static int makesock(port, proto, socksz)
- int port;
- int proto;
- int socksz;
- {
- struct sockaddr_in sin;
- int s;
- int sock_type;
-
- sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
- s = socket(AF_INET, sock_type, proto);
- if (s < 0) {
- dprintf(0, "Could not make a socket: %s\n", strerror(errno));
- return (-1);
- }
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
-
- {
- int val = 1;
-
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
- dprintf(0, "setsockopt failed: %s\n", strerror(errno));
- }
-
- #ifdef SO_SNDBUF
- {
- int sblen, rblen;
-
- /* 1024 for rpc & transport overheads */
- sblen = rblen = socksz + 1024;
- if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0 ||
- setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof rblen) < 0)
- dprintf(0, "setsockopt failed: %s\n", strerror(errno));
- }
- #endif /* SO_SNDBUF */
-
- if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
- dprintf(0, "Could not bind name to socket: %s\n", strerror(errno));
- return (-1);
- }
- return (s);
- }
-
- /* This is taken from an rpcgen generated service file. */
- static void closedown(sig)
- int sig;
- {
- (void) signal(sig, closedown);
- if (_rpcsvcdirty == 0) {
- extern fd_set svc_fdset;
- static int size;
- int i, openfd;
-
- if (_rpcfdtype == SOCK_DGRAM)
- exit(0);
- if (size == 0) {
- size = getdtablesize();
- }
- for (i = 0, openfd = 0; i < size && openfd < 2; i++)
- if (FD_ISSET(i, &svc_fdset))
- openfd++;
- if (openfd <= 1)
- exit(0);
- }
- (void) alarm(_RPCSVC_CLOSEDOWN);
- }
-
- int main(argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- struct sockaddr_in saddr;
- int addr_size;
- SVCXPRT *transp;
- int nfs_socket;
- char *auth_file = NULL;
-
- /*
- * This code uses the RPC library functions in exactly the
- * same way a regular RPC application would.
- */
- nfs_socket = 0;
- _rpcfdtype = 0;
- if (getsockname(0, (struct sockaddr *) &saddr, &addr_size) == 0) {
- int ssize = sizeof(int);
- if (saddr.sin_family != AF_INET)
- exit(1);
- if (getsockopt(0, SOL_SOCKET, SO_TYPE,
- (char *) &_rpcfdtype, &ssize) < 0)
- exit(1);
- _rpcpmstart = 1;
- } else
- pmap_unset(NFS_PROGRAM, NFS_VERSION);
-
- if (_rpcfdtype == 0 || _rpcfdtype == SOCK_DGRAM) {
- if (_rpcfdtype == 0 &&
- (nfs_socket = makesock(NFS_PORT, IPPROTO_UDP, NFS_MAXDATA)) < 0) {
- fprintf(stderr, "nfsd: could not make a UDP socket.\n");
- exit(1);
- }
- transp = svcudp_create(nfs_socket);
- if (transp == NULL) {
- fprintf(stderr, "nfsd: cannot create UDP service.\n");
- exit(1);
- }
- if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_dispatch,
- IPPROTO_UDP)) {
- fprintf(stderr,
- "unable to register(NFS_PROGRAM, NFS_VERSION, UDP).\n");
- exit(1);
- }
- }
- if (_rpcfdtype == 0 || _rpcfdtype == SOCK_STREAM) {
- if (_rpcfdtype == 0 &&
- (nfs_socket = makesock(NFS_PORT, IPPROTO_TCP, NFS_MAXDATA)) < 0) {
- fprintf(stderr, "nfsd: could not make a TCP socket.\n");
- exit(1);
- }
- transp = svctcp_create(nfs_socket, 0, 0);
- if (transp == NULL) {
- fprintf(stderr, "nfsd: cannot create TCP service.\n");
- exit(1);
- }
- if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_dispatch,
- IPPROTO_TCP)) {
- fprintf(stderr,
- "unable to register(NFS_PROGRAM, NFS_VERSION, TCP).\n");
- exit(1);
- }
- }
-
- program_name = argv[0];
-
- /* Parse the command line options and arguments. */
- opterr = 0;
- while ((c = getopt_long(argc, argv, "df:hnprv", longopts, NULL)) != EOF)
- switch (c) {
- case 'h':
- usage(stdout, 0);
- break;
- case 'd':
- toggle_logging(0);
- break;
- case 'f':
- auth_file = optarg;
- break;
- case 'n':
- allow_non_root = 1;
- break;
- case 'p':
- promiscuous = 1;
- break;
- case 'r':
- re_export = 1;
- break;
- case 'v':
- printf("%s\n", version);
- exit(0);
- case 0:
- break;
- case '?':
- default:
- usage(stderr, 1);
- }
-
- /* No more arguments allowed. */
- if (optind != argc)
- usage(stderr, 1);
-
- /* We first fork off a child. */
- if ((c = fork()) > 0)
- exit(0);
- if (c < 0) {
- fprintf(stderr, "nfsd: cannot fork: %s\n", strerror(errno));
- exit(-1);
- }
- /* Now we remove ourselves from the foreground. */
- (void) close(0);
- (void) close(1);
- (void) close(2);
- #ifdef HAVE_SETSID
- setsid();
- #else
- {
- int fd;
-
- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
- (void) ioctl(fd, TIOCNOTTY, (char *) NULL);
- (void) close(fd);
- }
- }
- #endif
- /* Initialize logging. */
- log_open("nfsd");
-
- /* Initialize the FH module. */
- fh_init();
-
- /* Initialize the AUTH module. */
- auth_init(auth_file);
-
- /* Enable the LOG toggle with a signal. */
- signal(SIGUSR1, toggle_logging);
-
- if (_rpcpmstart) {
- signal(SIGALRM, closedown);
- alarm(_RPCSVC_CLOSEDOWN);
- }
- /* Run the NFS server. */
- svc_run();
-
- dprintf(0, "Oh no Mr. Bill... nfs_server() returned!\n");
- exit(1);
- }
-
- static void usage(fp, n)
- FILE *fp;
- int n;
- {
- fprintf(fp, "Usage: %s [-dhnpv] [-f exports-file]\n", program_name);
- fprintf(fp, " [--debug] [--help] [--allow-non-root]\n");
- fprintf(fp, " [--promiscuous] [--version]\n");
- fprintf(fp, " [--exports-file=file]\n");
- exit(n);
- }
-
-