The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/lib/libshare/nfs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 
   22 
   23 #include <sys/types.h>
   24 #include <sys/stat.h>
   25 #include <sys/file.h>
   26 #include <fcntl.h>
   27 #include <ctype.h>
   28 #include <stdio.h>
   29 #include <errno.h>
   30 #include <libshare.h>
   31 #include <unistd.h>
   32 #include "nfs.h"
   33 
   34 
   35 /*
   36  * nfs_exports_[lock|unlock] are used to guard against conconcurrent
   37  * updates to the exports file. Each protocol is responsible for
   38  * providing the necessary locking to ensure consistency.
   39  */
   40 static int
   41 nfs_exports_lock(const char *name, int *nfs_lock_fd)
   42 {
   43         int err;
   44 
   45         *nfs_lock_fd = open(name, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
   46         if (*nfs_lock_fd == -1) {
   47                 err = errno;
   48                 fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
   49                 return (err);
   50         }
   51 
   52         while ((err = flock(*nfs_lock_fd, LOCK_EX)) != 0 && errno == EINTR)
   53                 ;
   54         if (err != 0) {
   55                 err = errno;
   56                 fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
   57                 (void) close(*nfs_lock_fd);
   58                 *nfs_lock_fd = -1;
   59                 return (err);
   60         }
   61 
   62         return (0);
   63 }
   64 
   65 static void
   66 nfs_exports_unlock(const char *name, int *nfs_lock_fd)
   67 {
   68         verify(*nfs_lock_fd > 0);
   69 
   70         if (flock(*nfs_lock_fd, LOCK_UN) != 0)
   71                 fprintf(stderr, "failed to unlock %s: %s\n",
   72                     name, strerror(errno));
   73 
   74         (void) close(*nfs_lock_fd);
   75         *nfs_lock_fd = -1;
   76 }
   77 
   78 struct tmpfile {
   79         /*
   80          * This only needs to be as wide as ZFS_EXPORTS_FILE and mktemp suffix,
   81          * 64 is more than enough.
   82          */
   83         char name[64];
   84         FILE *fp;
   85 };
   86 
   87 static boolean_t
   88 nfs_init_tmpfile(const char *prefix, const char *mdir, struct tmpfile *tmpf)
   89 {
   90         if (mdir != NULL &&
   91             mkdir(mdir, 0755) < 0 &&
   92             errno != EEXIST) {
   93                 fprintf(stderr, "failed to create %s: %s\n",
   94                 // cppcheck-suppress uninitvar
   95                     mdir, strerror(errno));
   96                 return (B_FALSE);
   97         }
   98 
   99         strlcpy(tmpf->name, prefix, sizeof (tmpf->name));
  100         strlcat(tmpf->name, ".XXXXXXXX", sizeof (tmpf->name) - strlen(prefix));
  101 
  102         int fd = mkostemp(tmpf->name, O_CLOEXEC);
  103         if (fd == -1) {
  104                 fprintf(stderr, "Unable to create temporary file: %s",
  105                     strerror(errno));
  106                 return (B_FALSE);
  107         }
  108 
  109         tmpf->fp = fdopen(fd, "w+");
  110         if (tmpf->fp == NULL) {
  111                 fprintf(stderr, "Unable to reopen temporary file: %s",
  112                     strerror(errno));
  113                 close(fd);
  114                 return (B_FALSE);
  115         }
  116 
  117         return (B_TRUE);
  118 }
  119 
  120 static void
  121 nfs_abort_tmpfile(struct tmpfile *tmpf)
  122 {
  123         unlink(tmpf->name);
  124         fclose(tmpf->fp);
  125 }
  126 
  127 static int
  128 nfs_fini_tmpfile(const char *exports, struct tmpfile *tmpf)
  129 {
  130         if (fflush(tmpf->fp) != 0) {
  131                 fprintf(stderr, "Failed to write to temporary file: %s\n",
  132                     strerror(errno));
  133                 nfs_abort_tmpfile(tmpf);
  134                 return (SA_SYSTEM_ERR);
  135         }
  136 
  137         if (rename(tmpf->name, exports) == -1) {
  138                 fprintf(stderr, "Unable to rename %s -> %s: %s\n",
  139                     tmpf->name, exports, strerror(errno));
  140                 nfs_abort_tmpfile(tmpf);
  141                 return (SA_SYSTEM_ERR);
  142         }
  143 
  144         (void) fchmod(fileno(tmpf->fp), 0644);
  145         fclose(tmpf->fp);
  146         return (SA_OK);
  147 }
  148 
  149 int
  150 nfs_escape_mountpoint(const char *mp, char **out, boolean_t *need_free)
  151 {
  152         if (strpbrk(mp, "\t\n\v\f\r \\") == NULL) {
  153                 *out = (char *)mp;
  154                 *need_free = B_FALSE;
  155                 return (SA_OK);
  156         } else {
  157                 size_t len = strlen(mp);
  158                 *out = malloc(len * 4 + 1);
  159                 if (!*out)
  160                         return (SA_NO_MEMORY);
  161                 *need_free = B_TRUE;
  162 
  163                 char *oc = *out;
  164                 for (const char *c = mp; c < mp + len; ++c)
  165                         if (memchr("\t\n\v\f\r \\", *c,
  166                             strlen("\t\n\v\f\r \\"))) {
  167                                 sprintf(oc, "\\%03hho", *c);
  168                                 oc += 4;
  169                         } else
  170                                 *oc++ = *c;
  171                 *oc = '\0';
  172         }
  173 
  174         return (SA_OK);
  175 }
  176 
  177 static int
  178 nfs_process_exports(const char *exports, const char *mountpoint,
  179     boolean_t (*cbk)(void *userdata, char *line, boolean_t found_mountpoint),
  180     void *userdata)
  181 {
  182         int error = SA_OK;
  183         boolean_t cont = B_TRUE;
  184 
  185         FILE *oldfp = fopen(exports, "re");
  186         if (oldfp != NULL) {
  187                 boolean_t need_mp_free;
  188                 char *mp;
  189                 if ((error = nfs_escape_mountpoint(mountpoint,
  190                     &mp, &need_mp_free)) != SA_OK) {
  191                         (void) fclose(oldfp);
  192                         return (error);
  193                 }
  194 
  195                 char *buf = NULL, *sep;
  196                 size_t buflen = 0, mplen = strlen(mp);
  197 
  198                 while (cont && getline(&buf, &buflen, oldfp) != -1) {
  199                         if (buf[0] == '\n' || buf[0] == '#')
  200                                 continue;
  201 
  202                         cont = cbk(userdata, buf,
  203                             (sep = strpbrk(buf, "\t \n")) != NULL &&
  204                             sep - buf == mplen &&
  205                             strncmp(buf, mp, mplen) == 0);
  206                 }
  207                 free(buf);
  208                 if (need_mp_free)
  209                         free(mp);
  210 
  211                 if (ferror(oldfp) != 0)
  212                         error = ferror(oldfp);
  213 
  214                 if (fclose(oldfp) != 0) {
  215                         fprintf(stderr, "Unable to close file %s: %s\n",
  216                             exports, strerror(errno));
  217                         error = error != SA_OK ? error : SA_SYSTEM_ERR;
  218                 }
  219         }
  220 
  221         return (error);
  222 }
  223 
  224 static boolean_t
  225 nfs_copy_entries_cb(void *userdata, char *line, boolean_t found_mountpoint)
  226 {
  227         FILE *newfp = userdata;
  228         if (!found_mountpoint)
  229                 fputs(line, newfp);
  230         return (B_TRUE);
  231 }
  232 
  233 /*
  234  * Copy all entries from the exports file (if it exists) to newfp,
  235  * omitting any entries for the specified mountpoint.
  236  */
  237 static int
  238 nfs_copy_entries(FILE *newfp, const char *exports, const char *mountpoint)
  239 {
  240         fputs(FILE_HEADER, newfp);
  241 
  242         int error = nfs_process_exports(
  243             exports, mountpoint, nfs_copy_entries_cb, newfp);
  244 
  245         if (error == SA_OK && ferror(newfp) != 0)
  246                 error = ferror(newfp);
  247 
  248         return (error);
  249 }
  250 
  251 int
  252 nfs_toggle_share(const char *lockfile, const char *exports,
  253     const char *expdir, sa_share_impl_t impl_share,
  254     int(*cbk)(sa_share_impl_t impl_share, FILE *tmpfile))
  255 {
  256         int error, nfs_lock_fd = -1;
  257         struct tmpfile tmpf;
  258 
  259         if (!nfs_init_tmpfile(exports, expdir, &tmpf))
  260                 return (SA_SYSTEM_ERR);
  261 
  262         error = nfs_exports_lock(lockfile, &nfs_lock_fd);
  263         if (error != 0) {
  264                 nfs_abort_tmpfile(&tmpf);
  265                 return (error);
  266         }
  267 
  268         error = nfs_copy_entries(tmpf.fp, exports, impl_share->sa_mountpoint);
  269         if (error != SA_OK)
  270                 goto fullerr;
  271 
  272         error = cbk(impl_share, tmpf.fp);
  273         if (error != SA_OK)
  274                 goto fullerr;
  275 
  276         error = nfs_fini_tmpfile(exports, &tmpf);
  277         nfs_exports_unlock(lockfile, &nfs_lock_fd);
  278         return (error);
  279 
  280 fullerr:
  281         nfs_abort_tmpfile(&tmpf);
  282         nfs_exports_unlock(lockfile, &nfs_lock_fd);
  283         return (error);
  284 }
  285 
  286 void
  287 nfs_reset_shares(const char *lockfile, const char *exports)
  288 {
  289         int nfs_lock_fd = -1;
  290 
  291         if (nfs_exports_lock(lockfile, &nfs_lock_fd) == 0) {
  292                 (void) ! truncate(exports, 0);
  293                 nfs_exports_unlock(lockfile, &nfs_lock_fd);
  294         }
  295 }
  296 
  297 static boolean_t
  298 nfs_is_shared_cb(void *userdata, char *line, boolean_t found_mountpoint)
  299 {
  300         (void) line;
  301 
  302         boolean_t *found = userdata;
  303         *found = found_mountpoint;
  304         return (!found_mountpoint);
  305 }
  306 
  307 boolean_t
  308 nfs_is_shared_impl(const char *exports, sa_share_impl_t impl_share)
  309 {
  310         boolean_t found = B_FALSE;
  311         nfs_process_exports(exports, impl_share->sa_mountpoint,
  312             nfs_is_shared_cb, &found);
  313         return (found);
  314 }

Cache object: 9450edd8ff021809f1cd26a88ab670c7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.