ANSI fixes (one real bug!)
[unix-history] / usr / src / sbin / mountd / mountd.c
index 73e0d24..73e1ddb 100644 (file)
@@ -5,17 +5,7 @@
  * This code is derived from software contributed to Berkeley by
  * Rick Macklem at The University of Guelph.
  *
  * This code is derived from software contributed to Berkeley by
  * Rick Macklem at The University of Guelph.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
@@ -25,31 +15,27 @@ char copyright[] =
 #endif not lint
 
 #ifndef lint
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)mountd.c   5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)mountd.c   5.13 (Berkeley) %G%";
 #endif not lint
 
 #endif not lint
 
-#include <stdio.h>
-#include <strings.h>
-#include <syslog.h>
-#include <signal.h>
-#include <fcntl.h>
 #include <sys/param.h>
 #include <sys/param.h>
-#include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
-#include <sys/dir.h>
-#include <sys/uio.h>
-#include <sys/namei.h>
+#include <sys/file.h>
 #include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/mount.h>
 #include <sys/socket.h>
-#include <sys/socketvar.h>
 #include <sys/errno.h>
 #include <sys/errno.h>
+#include <sys/signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
 #include <netdb.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpc/pmap_prot.h>
 #include <nfs/rpcv2.h>
 #include <nfs/nfsv2.h>
 #include <netdb.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 #include <rpc/pmap_prot.h>
 #include <nfs/rpcv2.h>
 #include <nfs/nfsv2.h>
+#include "pathnames.h"
 
 struct ufid {
        u_short ufid_len;
 
 struct ufid {
        u_short ufid_len;
@@ -61,7 +47,6 @@ struct ufid {
  */
 struct mountlist {
        struct mountlist *ml_next;
  */
 struct mountlist {
        struct mountlist *ml_next;
-       struct mountlist *ml_prev;
        char    ml_host[RPCMNT_NAMELEN+1];
        char    ml_dirp[RPCMNT_PATHLEN+1];
 };
        char    ml_host[RPCMNT_NAMELEN+1];
        char    ml_dirp[RPCMNT_PATHLEN+1];
 };
@@ -72,21 +57,24 @@ struct exportlist {
        struct grouplist *ex_groups;
        int     ex_rootuid;
        int     ex_exflags;
        struct grouplist *ex_groups;
        int     ex_rootuid;
        int     ex_exflags;
+       dev_t   ex_dev;
        char    ex_dirp[RPCMNT_PATHLEN+1];
 };
 
 struct grouplist {
        struct grouplist *gr_next;
        char    ex_dirp[RPCMNT_PATHLEN+1];
 };
 
 struct grouplist {
        struct grouplist *gr_next;
-       char    gr_name[RPCMNT_NAMELEN+1];
+       struct hostent *gr_hp;
 };
 
 /* Global defs */
 int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
 };
 
 /* Global defs */
 int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
-int mntsrv(), get_exportlist();
+int mntsrv(), get_exportlist(), send_umntall(), umntall_each();
+void get_mountlist(), add_mlist(), del_mlist();
 struct exportlist exphead;
 struct exportlist exphead;
-struct mountlist mlhead;
+struct mountlist *mlhead;
 char exname[MAXPATHLEN];
 int def_rootuid = -2;
 char exname[MAXPATHLEN];
 int def_rootuid = -2;
+int root_only = 1;
 extern int errno;
 #ifdef DEBUG
 int debug = 1;
 extern int errno;
 #ifdef DEBUG
 int debug = 1;
@@ -96,52 +84,54 @@ int debug = 0;
 
 /*
  * Mountd server for NFS mount protocol as described in:
 
 /*
  * Mountd server for NFS mount protocol as described in:
- *  Networking on the Sun Workstation,
- *  Part #800-1324-03 Rev. B
- *  Network File System Protocol Specification Chap. 3
- * The optional argument is the exports file name
- * default: /etc/exports
+ * NFS: Network File System Protocol Specification, RFC1094, Appendix A
+ * The optional arguments are the exports file name
+ * default: _PATH_EXPORTS
+ * and "-n" to allow nonroot mount.
  */
 main(argc, argv)
        int argc;
  */
 main(argc, argv)
        int argc;
-       char *argv[];
+       char **argv;
 {
        SVCXPRT *transp;
 {
        SVCXPRT *transp;
+       int c;
+       extern int optind;
+       extern char *optarg;
 
 
-       if (debug == 0) {
-               if (fork())
-                       exit(0);
-               { int s;
-               for (s = 0; s < 10; s++)
-                       (void) close(s);
-               }
-               (void) open("/", O_RDONLY);
-               (void) dup2(0, 1);
-               (void) dup2(0, 2);
-               { int tt = open("/dev/tty", O_RDWR);
-                 if (tt > 0) {
-                       ioctl(tt, TIOCNOTTY, (char *)0);
-                       close(tt);
-                 }
-               }
-               (void) setpgrp(0, 0);
-               signal(SIGTSTP, SIG_IGN);
-               signal(SIGTTIN, SIG_IGN);
-               signal(SIGTTOU, SIG_IGN);
-               signal(SIGINT, SIG_IGN);
-               signal(SIGQUIT, SIG_IGN);
-               signal(SIGTERM, SIG_IGN);
-       }
-       openlog("mountd:", LOG_PID, LOG_DAEMON);
-       mlhead.ml_next = mlhead.ml_prev = (struct mountlist *)0;
+       while ((c = getopt(argc, argv, "n")) != EOF)
+               switch (c) {
+               case 'n':
+                       root_only = 0;
+                       break;
+               default:
+                       fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
+                       exit(1);
+               };
+       argc -= optind;
+       argv += optind;
        exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
        exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
-       if (argc == 2) {
-               strncpy(exname, argv[1], MAXPATHLEN-1);
+       mlhead = (struct mountlist *)0;
+       if (argc == 1) {
+               strncpy(exname, *argv, MAXPATHLEN-1);
                exname[MAXPATHLEN-1] = '\0';
        } else
                exname[MAXPATHLEN-1] = '\0';
        } else
-               strcpy(exname, "/etc/exports");
+               strcpy(exname, _PATH_EXPORTS);
+       openlog("mountd:", LOG_PID, LOG_DAEMON);
        get_exportlist();
        get_exportlist();
+       get_mountlist();
+       if (debug == 0) {
+               daemon(0, 0);
+               signal(SIGINT, SIG_IGN);
+               signal(SIGQUIT, SIG_IGN);
+       }
        signal(SIGHUP, get_exportlist);
        signal(SIGHUP, get_exportlist);
+       signal(SIGTERM, send_umntall);
+       { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
+         if (pidfile != NULL) {
+               fprintf(pidfile, "%d\n", getpid());
+               fclose(pidfile);
+         }
+       }
        if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
                syslog(LOG_ERR, "Can't create socket");
                exit(1);
        if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
                syslog(LOG_ERR, "Can't create socket");
                exit(1);
@@ -153,6 +143,7 @@ main(argc, argv)
        }
        svc_run();
        syslog(LOG_ERR, "Mountd died");
        }
        svc_run();
        syslog(LOG_ERR, "Mountd died");
+       exit(1);
 }
 
 /*
 }
 
 /*
@@ -162,65 +153,47 @@ mntsrv(rqstp, transp)
        register struct svc_req *rqstp;
        register SVCXPRT *transp;
 {
        register struct svc_req *rqstp;
        register SVCXPRT *transp;
 {
-       register struct mountlist *mlp;
-       register struct exportlist *ep;
        register struct grouplist *grp;
        register struct grouplist *grp;
-       struct mountlist *mlp2;
+       register u_long **addrp;
+       register struct exportlist *ep;
        nfsv2fh_t nfh;
        struct authunix_parms *ucr;
        struct stat stb;
        struct hostent *hp;
        nfsv2fh_t nfh;
        struct authunix_parms *ucr;
        struct stat stb;
        struct hostent *hp;
-       struct sockaddr_in saddr;
+       u_long saddr;
        char dirpath[RPCMNT_PATHLEN+1];
        char dirpath[RPCMNT_PATHLEN+1];
-       int ok = 0;
        int bad = ENOENT;
        int omask;
        int bad = ENOENT;
        int omask;
-
-fprintf(stderr,"in mntsrv\n");
-       if (rqstp->rq_proc == NULLPROC) {
-               if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
-                       syslog(LOG_ERR, "Can't send reply");
-               return;
-       }
+       uid_t uid = -2;
 
        /* Get authorization */
        switch (rqstp->rq_cred.oa_flavor) {
        case AUTH_UNIX:
                ucr = (struct authunix_parms *)rqstp->rq_clntcred;
 
        /* Get authorization */
        switch (rqstp->rq_cred.oa_flavor) {
        case AUTH_UNIX:
                ucr = (struct authunix_parms *)rqstp->rq_clntcred;
-               if (ucr->aup_uid == 0)
-                       break;
-               /* Fall thru to */
-fprintf(stderr,"weak auth\n");
+               uid = ucr->aup_uid;
+               break;
        case AUTH_NULL:
        default:
        case AUTH_NULL:
        default:
-               svcerr_weakauth(transp);
-               return;
+               break;
        }
 
        }
 
-       saddr.sin_family = AF_INET;
-       saddr.sin_addr.s_addr = ntohl(transp->xp_raddr.sin_addr.s_addr);
-       saddr.sin_port = 0;
-       hp = gethostbyaddr((caddr_t)&saddr, transp->xp_addrlen, AF_INET);
-fprintf(stderr,"net_addr=0x%x\n",transp->xp_raddr.sin_addr.s_addr);
-fprintf(stderr,"aft gethost hp=0x%x\n",hp);
+       saddr = transp->xp_raddr.sin_addr.s_addr;
+       hp = (struct hostent *)0;
        switch (rqstp->rq_proc) {
        switch (rqstp->rq_proc) {
+       case NULLPROC:
+               if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
+                       syslog(LOG_ERR, "Can't send reply");
+               return;
        case RPCMNT_MOUNT:
        case RPCMNT_MOUNT:
-fprintf(stderr,"in mnt req\n");
-               if (!svc_getargs(transp, xdr_dir, dirpath)) {
-                       svcerr_decode(transp);
+               if (uid != 0 && root_only) {
+                       svcerr_weakauth(transp);
                        return;
                }
                        return;
                }
-
-fprintf(stderr,"dirpath=%s\n",dirpath);
-               /* If no hostname, return err */
-#ifdef notdef
-               if (hp == NULL) {
-                       if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
-                               syslog(LOG_ERR, "Can't send reply");
+               if (!svc_getargs(transp, xdr_dir, dirpath)) {
+                       svcerr_decode(transp);
                        return;
                }
 
                        return;
                }
 
-#endif
                /* Check to see if it's a valid dirpath */
                if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
                        S_IFDIR) {
                /* Check to see if it's a valid dirpath */
                if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
                        S_IFDIR) {
@@ -229,7 +202,6 @@ fprintf(stderr,"dirpath=%s\n",dirpath);
                        return;
                }
 
                        return;
                }
 
-fprintf(stderr,"Look in exports list\n");
                /* Check in the exports list */
                omask = sigblock(sigmask(SIGHUP));
                ep = exphead.ex_next;
                /* Check in the exports list */
                omask = sigblock(sigmask(SIGHUP));
                ep = exphead.ex_next;
@@ -238,16 +210,26 @@ fprintf(stderr,"Look in exports list\n");
                                grp = ep->ex_groups;
                                if (grp == NULL)
                                        break;
                                grp = ep->ex_groups;
                                if (grp == NULL)
                                        break;
-                               while (grp != NULL) {
-                                       if (!strcmp(grp->gr_name, hp->h_name))
+
+                               /* Check for a host match */
+                               addrp = (u_long **)grp->gr_hp->h_addr_list;
+                               for (;;) {
+                                       if (**addrp == saddr)
                                                break;
                                                break;
-                                       grp = grp->gr_next;
+                                       if (*++addrp == NULL)
+                                               if (grp = grp->gr_next) {
+                                                       addrp = (u_long **)
+                                                               grp->gr_hp->h_addr_list;
+                                               } else {
+                                                       bad = EACCES;
+                                                       if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
+                                                               syslog(LOG_ERR, "Can't send reply");
+                                                       sigsetmask(omask);
+                                                       return;
+                                               }
                                }
                                }
-                               bad = EACCES;
-                               if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
-                                       syslog(LOG_ERR, "Can't send reply");
-                               sigsetmask(omask);
-                               return;
+                               hp = grp->gr_hp;
+                               break;
                        }
                        ep = ep->ex_next;
                }
                        }
                        ep = ep->ex_next;
                }
@@ -259,7 +241,6 @@ fprintf(stderr,"Look in exports list\n");
                        return;
                }
 
                        return;
                }
 
-fprintf(stderr,"get file handle\n");
                /* Get the file handle */
                bzero((caddr_t)&nfh, sizeof(nfh));
                if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
                /* Get the file handle */
                bzero((caddr_t)&nfh, sizeof(nfh));
                if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
@@ -268,73 +249,42 @@ fprintf(stderr,"get file handle\n");
                                syslog(LOG_ERR, "Can't send reply");
                        return;
                }
                                syslog(LOG_ERR, "Can't send reply");
                        return;
                }
-{ struct ufid *ufp;
-ufp = (struct ufid *)&nfh.fh_generic;
-fprintf(stderr,"ftyp=%d fnum=%d\n",nfh.fh_generic.fh_fsid.val[1],
-nfh.fh_generic.fh_fsid.val[0]);
-fprintf(stderr,"fid num=%d gen=%d\n",ufp->ufid_ino,ufp->ufid_gen);
-}
                if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
                        syslog(LOG_ERR, "Can't send reply");
                if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
                        syslog(LOG_ERR, "Can't send reply");
-               mlp = (struct mountlist *)malloc(sizeof(struct mountlist));
-fprintf(stderr,"add to list\n");
-#ifdef notdef
-               if (mlp != NULL) {
-                       strcpy(mlp->ml_host, hp->h_name);
-                       strcpy(mlp->ml_dirp, dirpath);
-                       mlp->ml_prev = &mlhead;
-                       mlp->ml_next = mlhead.ml_next;
-                       if (mlhead.ml_next != NULL)
-                               mlhead.ml_next->ml_prev = mlp;
-                       mlhead.ml_next = mlp;
-               }
-#endif
+               if (hp == NULL)
+                       hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+               if (hp)
+                       add_mlist(hp->h_name, dirpath);
                return;
        case RPCMNT_DUMP:
                if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
                        syslog(LOG_ERR, "Can't send reply");
                return;
        case RPCMNT_UMOUNT:
                return;
        case RPCMNT_DUMP:
                if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
                        syslog(LOG_ERR, "Can't send reply");
                return;
        case RPCMNT_UMOUNT:
+               if (uid != 0 && root_only) {
+                       svcerr_weakauth(transp);
+                       return;
+               }
                if (!svc_getargs(transp, xdr_dir, dirpath)) {
                        svcerr_decode(transp);
                        return;
                }
                if (!svc_getargs(transp, xdr_dir, dirpath)) {
                        svcerr_decode(transp);
                        return;
                }
-               if (hp != NULL) {
-                       mlp = mlhead.ml_next;
-                       while (mlp != NULL) {
-                               if (!strcmp(mlp->ml_host, hp->h_name) &&
-                                   !strcmp(mlp->ml_dirp, dirpath)) {
-                                       mlp->ml_prev->ml_next = mlp->ml_next;
-                                       if (mlp->ml_next != NULL)
-                                               mlp->ml_next->ml_prev =
-                                                  mlp->ml_prev;
-                                       free((caddr_t)mlp);
-                                       break;
-                               }
-                               mlp = mlp->ml_next;
-                       }
-               }
                if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
                        syslog(LOG_ERR, "Can't send reply");
                if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
                        syslog(LOG_ERR, "Can't send reply");
+               hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+               if (hp)
+                       del_mlist(hp->h_name, dirpath);
                return;
        case RPCMNT_UMNTALL:
                return;
        case RPCMNT_UMNTALL:
-               if (hp != NULL) {
-                       mlp = mlhead.ml_next;
-                       while (mlp != NULL) {
-                               if (!strcmp(mlp->ml_host, hp->h_name)) {
-                                       mlp2 = mlp;
-                                       mlp->ml_prev->ml_next = mlp->ml_next;
-                                       if (mlp->ml_next != NULL)
-                                               mlp->ml_next->ml_prev =
-                                                  mlp->ml_prev;
-                                       mlp = mlp->ml_next;
-                                       free((caddr_t)mlp2);
-                               } else
-                                       mlp = mlp->ml_next;
-                       }
+               if (uid != 0 && root_only) {
+                       svcerr_weakauth(transp);
+                       return;
                }
                if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
                        syslog(LOG_ERR, "Can't send reply");
                }
                if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
                        syslog(LOG_ERR, "Can't send reply");
+               hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+               if (hp)
+                       del_mlist(hp->h_name, (char *)0);
                return;
        case RPCMNT_EXPORT:
                if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
                return;
        case RPCMNT_EXPORT:
                if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
@@ -367,7 +317,6 @@ xdr_fhs(xdrsp, nfh)
 
        if (!xdr_long(xdrsp, &ok))
                return (0);
 
        if (!xdr_long(xdrsp, &ok))
                return (0);
-fprintf(stderr,"eo xdr_fhs\n");
        return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
 }
 
        return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
 }
 
@@ -380,8 +329,8 @@ xdr_mlist(xdrsp, cp)
        int false = 0;
        char *strp;
 
        int false = 0;
        char *strp;
 
-       mlp = mlhead.ml_next;
-       while (mlp != NULL) {
+       mlp = mlhead;
+       while (mlp) {
                if (!xdr_bool(xdrsp, &true))
                        return (0);
                strp = &mlp->ml_host[0];
                if (!xdr_bool(xdrsp, &true))
                        return (0);
                strp = &mlp->ml_host[0];
@@ -423,7 +372,7 @@ xdr_explist(xdrsp, cp)
                while (grp != NULL) {
                        if (!xdr_bool(xdrsp, &true))
                                goto errout;
                while (grp != NULL) {
                        if (!xdr_bool(xdrsp, &true))
                                goto errout;
-                       strp = &grp->gr_name[0];
+                       strp = grp->gr_hp->h_name;
                        if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
                                goto errout;
                        grp = grp->gr_next;
                        if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
                                goto errout;
                        grp = grp->gr_next;
@@ -449,27 +398,30 @@ char line[LINESIZ];
  */
 get_exportlist()
 {
  */
 get_exportlist()
 {
+       register struct hostent *hp, *nhp;
+       register char **addrp, **naddrp;
+       register int i;
+       register struct grouplist *grp;
        register struct exportlist *ep, *ep2;
        register struct exportlist *ep, *ep2;
-       register struct grouplist *grp, *grp2;
+       struct statfs stfsbuf;
+       struct ufs_args args;
+       struct stat sb;
        FILE *inf;
        char *cp, *endcp;
        FILE *inf;
        char *cp, *endcp;
-       int len;
+       char savedc;
+       int len, dirplen;
        int rootuid, exflags;
        int rootuid, exflags;
+       u_long saddr;
+       struct exportlist *fep;
 
        /*
         * First, get rid of the old list
         */
        ep = exphead.ex_next;
        while (ep != NULL) {
 
        /*
         * First, get rid of the old list
         */
        ep = exphead.ex_next;
        while (ep != NULL) {
-               grp = ep->ex_groups;
-               while (grp != NULL) {
-                       grp2 = grp;
-                       grp = grp->gr_next;
-                       free((caddr_t)grp2);
-               }
                ep2 = ep;
                ep = ep->ex_next;
                ep2 = ep;
                ep = ep->ex_next;
-               free((caddr_t)ep2);
+               free_exp(ep2);
        }
 
        /*
        }
 
        /*
@@ -482,71 +434,168 @@ get_exportlist()
                exit(2);
        }
        while (fgets(line, LINESIZ, inf)) {
                exit(2);
        }
        while (fgets(line, LINESIZ, inf)) {
-               exflags = 0;
+               exflags = MNT_EXPORTED;
                rootuid = def_rootuid;
                cp = line;
                nextfield(&cp, &endcp);
                rootuid = def_rootuid;
                cp = line;
                nextfield(&cp, &endcp);
+
+               /*
+                * Get file system devno and see if an entry for this
+                * file system already exists.
+                */
+               savedc = *endcp;
+               *endcp = '\0';
+               if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
+                       syslog(LOG_ERR,
+                           "Bad Exports File, %s: %s, mountd Failed",
+                           cp, "Not a directory");
+                       exit(2);
+               }
+               fep = (struct exportlist *)0;
+               ep = exphead.ex_next;
+               while (ep) {
+                       if (ep->ex_dev == sb.st_dev) {
+                               fep = ep;
+                               break;
+                       }
+                       ep = ep->ex_next;
+               }
+               *endcp = savedc;
+
+               /*
+                * Create new exports list entry
+                */
                len = endcp-cp;
                if (len <= RPCMNT_PATHLEN && len > 0) {
                        ep = (struct exportlist *)malloc(sizeof(*ep));
                len = endcp-cp;
                if (len <= RPCMNT_PATHLEN && len > 0) {
                        ep = (struct exportlist *)malloc(sizeof(*ep));
+                       if (ep == NULL)
+                               goto err;
                        ep->ex_next = ep->ex_prev = (struct exportlist *)0;
                        ep->ex_groups = (struct grouplist *)0;
                        bcopy(cp, ep->ex_dirp, len);
                        ep->ex_dirp[len] = '\0';
                        ep->ex_next = ep->ex_prev = (struct exportlist *)0;
                        ep->ex_groups = (struct grouplist *)0;
                        bcopy(cp, ep->ex_dirp, len);
                        ep->ex_dirp[len] = '\0';
-               } else
-                       goto err;
+                       dirplen = len;
+               } else {
+                       syslog(LOG_ERR, "Bad Exports File, mountd Failed");
+                       exit(2);
+               }
                cp = endcp;
                nextfield(&cp, &endcp);
                len = endcp-cp;
                while (len > 0) {
                cp = endcp;
                nextfield(&cp, &endcp);
                len = endcp-cp;
                while (len > 0) {
-                       if (len <= RPCMNT_NAMELEN) {
-                               if (*cp == '-') {
-                                       cp++;
-                                       switch (*cp) {
-                                       case 'o':
-                                               exflags |= M_EXRDONLY;
-                                               break;
-                                       case 'r':
-                                               if (*++cp == '=')
-                                                       rootuid = atoi(++cp);
-                                               break;
-                                       default:
-                                               syslog(LOG_WARNING,
-                                                 "Bad -%c option in %s",
-                                                 *cp, exname);
-                                               break;
-                                       };
-                               } else {
-                                       grp = (struct grouplist *)malloc(*grp);
-                                       if (grp == NULL)
-                                               goto err;
-                                       bcopy(cp, grp->gr_name, len);
-                                       grp->gr_name[len] = '\0';
-                                       grp->gr_next = ep->ex_groups;
-                                       ep->ex_groups = grp;
+                       savedc = *endcp;
+                       *endcp = '\0';
+                       if (len > RPCMNT_NAMELEN)
+                               goto more;
+                       if (*cp == '-') {
+                               do_opt(cp + 1, fep, ep, &exflags, &rootuid);
+                               goto more;
+                       }
+                       if (isdigit(*cp)) {
+                               saddr = inet_addr(cp);
+                               if (saddr == -1 ||
+                                   (hp = gethostbyaddr((caddr_t)&saddr,
+                                    sizeof(saddr), AF_INET)) == NULL) {
+                                       syslog(LOG_ERR,
+                                           "Bad Exports File, %s: %s", cp,
+                                           "Gethostbyaddr failed, ignored");
+                                       goto more;
                                }
                                }
+                       } else if ((hp = gethostbyname(cp)) == NULL) {
+                               syslog(LOG_ERR, "Bad Exports File, %s: %s",
+                                   cp, "Gethostbyname failed, ignored");
+                               goto more;
                        }
                        }
+                       grp = (struct grouplist *)
+                               malloc(sizeof(struct grouplist));
+                       if (grp == NULL)
+                               goto err;
+                       nhp = grp->gr_hp = (struct hostent *)
+                               malloc(sizeof(struct hostent));
+                       if (nhp == NULL)
+                               goto err;
+                       bcopy((caddr_t)hp, (caddr_t)nhp,
+                               sizeof(struct hostent));
+                       i = strlen(hp->h_name)+1;
+                       nhp->h_name = (char *)malloc(i);
+                       if (nhp->h_name == NULL)
+                               goto err;
+                       bcopy(hp->h_name, nhp->h_name, i);
+                       addrp = hp->h_addr_list;
+                       i = 1;
+                       while (*addrp++)
+                               i++;
+                       naddrp = nhp->h_addr_list = (char **)
+                               malloc(i*sizeof(char *));
+                       if (naddrp == NULL)
+                               goto err;
+                       addrp = hp->h_addr_list;
+                       while (*addrp) {
+                               *naddrp = (char *)
+                                   malloc(hp->h_length);
+                               if (*naddrp == NULL)
+                                   goto err;
+                               bcopy(*addrp, *naddrp,
+                                       hp->h_length);
+                               addrp++;
+                               naddrp++;
+                       }
+                       *naddrp = (char *)0;
+                       grp->gr_next = ep->ex_groups;
+                       ep->ex_groups = grp;
+               more:
                        cp = endcp;
                        cp = endcp;
+                       *cp = savedc;
                        nextfield(&cp, &endcp);
                        nextfield(&cp, &endcp);
-                       len = endcp-cp;
+                       len = endcp - cp;
                }
                }
-               if (exportfs(ep->ex_dirp, rootuid, exflags) < 0) {
-                       syslog(LOG_WARNING, "Can't export %s", ep->ex_dirp);
-                       free((caddr_t)ep);
-               } else {
+               if (fep == NULL) {
+                       args.fspec = 0;
+                       args.exflags = exflags;
+                       args.exroot = rootuid;
+                       cp = (char *)0;
+                       while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
+                              mount(MOUNT_UFS, ep->ex_dirp,
+                                    stfsbuf.f_flags|MNT_UPDATE, &args) < 0) {
+                               if (cp == NULL)
+                                       cp = ep->ex_dirp + dirplen - 1;
+                               else
+                                       *cp = savedc;
+                               /* back up over the last component */
+                               while (*cp == '/' && cp > ep->ex_dirp)
+                                       cp--;
+                               while (*(cp - 1) != '/' && cp > ep->ex_dirp)
+                                       cp--;
+                               if (cp == ep->ex_dirp) {
+                                       syslog(LOG_WARNING,
+                                             "Can't export %s", ep->ex_dirp);
+                                       free_exp(ep);
+                                       goto nextline;
+                               }
+                               savedc = *cp;
+                               *cp = '\0';
+                       }
+                       if (cp)
+                               *cp = savedc;
                        ep->ex_rootuid = rootuid;
                        ep->ex_exflags = exflags;
                        ep->ex_rootuid = rootuid;
                        ep->ex_exflags = exflags;
-                       ep->ex_next = exphead.ex_next;
-                       ep->ex_prev = &exphead;
-                       if (ep->ex_next != NULL)
-                               ep->ex_next->ex_prev = ep;
-                       exphead.ex_next = ep;
+               } else {
+                       ep->ex_rootuid = fep->ex_rootuid;
+                       ep->ex_exflags = fep->ex_exflags;
                }
                }
+               ep->ex_dev = sb.st_dev;
+               ep->ex_next = exphead.ex_next;
+               ep->ex_prev = &exphead;
+               if (ep->ex_next != NULL)
+                       ep->ex_next->ex_prev = ep;
+               exphead.ex_next = ep;
+nextline:
+               ;
        }
        fclose(inf);
        return;
 err:
        }
        fclose(inf);
        return;
 err:
-       syslog(LOG_ERR, "Bad /etc/exports, mountd Failed");
+       syslog(LOG_ERR, "No more memory: mountd Failed");
        exit(2);
 }
 
        exit(2);
 }
 
@@ -571,3 +620,194 @@ nextfield(cp, endcp)
                p++;
        *endcp = p;
 }
                p++;
        *endcp = p;
 }
+
+/*
+ * Parse the option string
+ */
+do_opt(cpopt, fep, ep, exflagsp, rootuidp)
+       register char *cpopt;
+       struct exportlist *fep, *ep;
+       int *exflagsp, *rootuidp;
+{
+       register char *cpoptarg, *cpoptend;
+
+       while (cpopt && *cpopt) {
+               if (cpoptend = index(cpopt, ','))
+                       *cpoptend++ = '\0';
+               if (cpoptarg = index(cpopt, '='))
+                       *cpoptarg++ = '\0';
+               if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
+                       if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
+                               syslog(LOG_WARNING, "ro failed for %s",
+                                      ep->ex_dirp);
+                       else
+                               *exflagsp |= MNT_EXRDONLY;
+               } else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
+                       if (cpoptarg && isdigit(*cpoptarg)) {
+                               *rootuidp = atoi(cpoptarg);
+                               if (fep && fep->ex_rootuid != *rootuidp)
+                                       syslog(LOG_WARNING,
+                                              "uid failed for %s",
+                                              ep->ex_dirp);
+                       } else
+                               syslog(LOG_WARNING,
+                                      "uid failed for %s",
+                                      ep->ex_dirp);
+               } else
+                       syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
+                              ep->ex_dirp);
+               cpopt = cpoptend;
+       }
+}
+
+#define        STRSIZ  (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
+/*
+ * Routines that maintain the remote mounttab
+ */
+void get_mountlist()
+{
+       register struct mountlist *mlp, **mlpp;
+       register char *eos, *dirp;
+       int len;
+       char str[STRSIZ];
+       FILE *mlfile;
+
+       if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
+           ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
+               syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
+               return;
+       }
+       mlpp = &mlhead;
+       while (fgets(str, STRSIZ, mlfile) != NULL) {
+               if ((dirp = index(str, '\t')) == NULL &&
+                   (dirp = index(str, ' ')) == NULL)
+                       continue;
+               mlp = (struct mountlist *)malloc(sizeof (*mlp));
+               len = dirp-str;
+               if (len > RPCMNT_NAMELEN)
+                       len = RPCMNT_NAMELEN;
+               bcopy(str, mlp->ml_host, len);
+               mlp->ml_host[len] = '\0';
+               while (*dirp == '\t' || *dirp == ' ')
+                       dirp++;
+               if ((eos = index(dirp, '\t')) == NULL &&
+                   (eos = index(dirp, ' ')) == NULL &&
+                   (eos = index(dirp, '\n')) == NULL)
+                       len = strlen(dirp);
+               else
+                       len = eos-dirp;
+               if (len > RPCMNT_PATHLEN)
+                       len = RPCMNT_PATHLEN;
+               bcopy(dirp, mlp->ml_dirp, len);
+               mlp->ml_dirp[len] = '\0';
+               mlp->ml_next = (struct mountlist *)0;
+               *mlpp = mlp;
+               mlpp = &mlp->ml_next;
+       }
+       fclose(mlfile);
+}
+
+void del_mlist(hostp, dirp)
+       register char *hostp, *dirp;
+{
+       register struct mountlist *mlp, **mlpp;
+       FILE *mlfile;
+       int fnd = 0;
+
+       mlpp = &mlhead;
+       mlp = mlhead;
+       while (mlp) {
+               if (!strcmp(mlp->ml_host, hostp) &&
+                   (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
+                       fnd = 1;
+                       *mlpp = mlp->ml_next;
+                       free((caddr_t)mlp);
+               }
+               mlpp = &mlp->ml_next;
+               mlp = mlp->ml_next;
+       }
+       if (fnd) {
+               if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
+                       syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
+                       return;
+               }
+               mlp = mlhead;
+               while (mlp) {
+                       fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
+                       mlp = mlp->ml_next;
+               }
+               fclose(mlfile);
+       }
+}
+
+void add_mlist(hostp, dirp)
+       register char *hostp, *dirp;
+{
+       register struct mountlist *mlp, **mlpp;
+       FILE *mlfile;
+
+       mlpp = &mlhead;
+       mlp = mlhead;
+       while (mlp) {
+               if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
+                       return;
+               mlpp = &mlp->ml_next;
+               mlp = mlp->ml_next;
+       }
+       mlp = (struct mountlist *)malloc(sizeof (*mlp));
+       strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
+       mlp->ml_host[RPCMNT_NAMELEN] = '\0';
+       strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
+       mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
+       mlp->ml_next = (struct mountlist *)0;
+       *mlpp = mlp;
+       if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
+               syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
+               return;
+       }
+       fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
+       fclose(mlfile);
+}
+
+/*
+ * This function is called via. SIGTERM when the system is going down.
+ * It sends a broadcast RPCMNT_UMNTALL.
+ */
+send_umntall()
+{
+       (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
+               xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
+       exit();
+}
+
+umntall_each(resultsp, raddr)
+       caddr_t resultsp;
+       struct sockaddr_in *raddr;
+{
+       return (1);
+}
+
+/*
+ * Free up an exports list component
+ */
+free_exp(ep)
+       register struct exportlist *ep;
+{
+       register struct grouplist *grp;
+       register char **addrp;
+       struct grouplist *grp2;
+
+       grp = ep->ex_groups;
+       while (grp != NULL) {
+               addrp = grp->gr_hp->h_addr_list;
+               while (*addrp)
+                       free(*addrp++);
+               free((caddr_t)grp->gr_hp->h_addr_list);
+               free(grp->gr_hp->h_name);
+               free((caddr_t)grp->gr_hp);
+               grp2 = grp;
+               grp = grp->gr_next;
+               free((caddr_t)grp2);
+       }
+       free((caddr_t)ep);
+}