]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mountd/rmtab.c
Open channel files O_WRONLY, and improve mountlist support.
[nfs-utils.git] / utils / mountd / rmtab.c
index 289a42e2b95fe0a0089ea71b7c65a0e010e60637..844de511f48b07d76baac5b0b828b9e5520af33f 100644 (file)
@@ -8,7 +8,9 @@
 
 #include "config.h"
 
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
 #include "xio.h"
 #include "mountd.h"
 
+#include <limits.h> /* PATH_MAX */
+
+/* If new path is a link do not destroy it but place the
+ * file where the link points.
+ */
+
+static int 
+slink_safe_rename(const char * oldpath, const char * newpath)
+{
+       int r;
+       struct stat s;
+       char slink_path[PATH_MAX];
+       const char *real_newpath = newpath;
+
+       if ((lstat(newpath, &s) == 0) && S_ISLNK(s.st_mode)) {
+               /* New path is a symbolic link, do not destroy but follow */
+               if ((r = readlink(newpath, slink_path, PATH_MAX - 1)) == -1)
+                       return -1;
+               slink_path[r] = '\0';
+               real_newpath = slink_path;
+       }
+
+       return rename(oldpath, real_newpath);
+}
+
 void
-mountlist_add(nfs_export *exp, const char *path)
+mountlist_add(char *host, const char *path)
 {
        struct rmtabent xe;
        struct rmtabent *rep;
        int             lockid;
+       long            pos;
 
        if ((lockid = xflock(_PATH_RMTAB, "a")) < 0)
                return;
-       setrmtabent("r");
-       while ((rep = getrmtabent(1)) != NULL) {
+       setrmtabent("r+");
+       while ((rep = getrmtabent(1, &pos)) != NULL) {
                if (strcmp (rep->r_client,
-                           exp->m_client->m_hostname) == 0
+                           host) == 0
                    && strcmp(rep->r_path, path) == 0) {
+                       rep->r_count++;
+                       putrmtabent(rep, &pos);
                        endrmtabent();
                        xfunlock(lockid);
                        return;
                }
        }
        endrmtabent();
-       strncpy(xe.r_client, exp->m_client->m_hostname,
+       strncpy(xe.r_client, host,
                sizeof (xe.r_client) - 1);
        xe.r_client [sizeof (xe.r_client) - 1] = '\0';
        strncpy(xe.r_path, path, sizeof (xe.r_path) - 1);
        xe.r_path [sizeof (xe.r_path) - 1] = '\0';
+       xe.r_count = 1;
        if (setrmtabent("a")) {
-               putrmtabent(&xe);
+               putrmtabent(&xe, NULL);
                endrmtabent();
        }
        xfunlock(lockid);
 }
 
 void
-mountlist_del(nfs_export *exp, const char *path)
+mountlist_del(char *hname, const char *path)
 {
        struct rmtabent *rep;
        FILE            *fp;
-       char            *hname = exp->m_client->m_hostname;
        int             lockid;
+       int             match;
 
        if ((lockid = xflock(_PATH_RMTAB, "w")) < 0)
                return;
@@ -69,12 +100,15 @@ mountlist_del(nfs_export *exp, const char *path)
                xfunlock(lockid);
                return;
        }
-       while ((rep = getrmtabent(1)) != NULL) {
-               if (strcmp (rep->r_client, hname)
-                   || strcmp(rep->r_path, path))
-                       fputrmtabent(fp, rep);
+       while ((rep = getrmtabent(1, NULL)) != NULL) {
+               match = !strcmp (rep->r_client, hname)
+                       && !strcmp(rep->r_path, path);
+               if (match)
+                       rep->r_count--;
+               if (!match || rep->r_count)
+                       fputrmtabent(fp, rep, NULL);
        }
-       if (rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
+       if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
                xlog(L_ERROR, "couldn't rename %s to %s",
                                _PATH_RMTABTMP, _PATH_RMTAB);
        }
@@ -114,15 +148,15 @@ mountlist_del_all(struct sockaddr_in *sin)
                free (hp);
                return;
        }
-       while ((rep = getrmtabent(1)) != NULL) {
+       while ((rep = getrmtabent(1, NULL)) != NULL) {
                if (strcmp(rep->r_client, hp->h_name) == 0 &&
                    (exp = auth_authenticate("umountall", sin, rep->r_path))) {
                        export_reset(exp);
                        continue;
                }
-               fputrmtabent(fp, rep);
+               fputrmtabent(fp, rep, NULL);
        }
-       if (rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
+       if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
                xlog(L_ERROR, "couldn't rename %s to %s",
                                _PATH_RMTABTMP, _PATH_RMTAB);
        }
@@ -158,7 +192,7 @@ mountlist_list(void)
                last_mtime = stb.st_mtime;
 
                setrmtabent("r");
-               while ((rep = getrmtabent(1)) != NULL) {
+               while ((rep = getrmtabent(1, NULL)) != NULL) {
                        m = (mountlist) xmalloc(sizeof(*m));
                        m->ml_hostname = xstrdup(rep->r_client);
                        m->ml_directory = xstrdup(rep->r_path);