diff --git a/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c.sav b/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c --- a/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c.sav +++ b/sys/contrib/openzfs/lib/libshare/os/freebsd/nfs.c @@ -44,8 +44,6 @@ #include "nfs.h" #define _PATH_MOUNTDPID "/var/run/mountd.pid" -#define OPTSSIZE 1024 -#define MAXLINESIZE (PATH_MAX + OPTSSIZE) #define ZFS_EXPORTS_FILE "/etc/zfs/exports" #define ZFS_EXPORTS_LOCK ZFS_EXPORTS_FILE".lock" @@ -69,17 +67,18 @@ * index, quiet */ static int -translate_opts(const char *shareopts, FILE *out) +translate_opts(char *oldopts, FILE *out) { static const char *const known_opts[] = { "ro", "maproot", "mapall", "mask", "network", "sec", "alldirs", "public", "webnfs", "index", "quiet" }; - char oldopts[OPTSSIZE], newopts[OPTSSIZE]; - char *o, *s = NULL; + char *newopts, *o, *s = NULL; unsigned int i; - size_t len; + size_t len, newopts_len; + int ret; - strlcpy(oldopts, shareopts, sizeof (oldopts)); + newopts_len = strlen(oldopts) + 1024; + newopts = malloc(newopts_len); newopts[0] = '\0'; s = oldopts; while ((o = strsep(&s, "-, ")) != NULL) { @@ -89,14 +88,16 @@ len = strlen(known_opts[i]); if (strncmp(known_opts[i], o, len) == 0 && (o[len] == '\0' || o[len] == '=')) { - strlcat(newopts, "-", sizeof (newopts)); + strlcat(newopts, "-", newopts_len); break; } } - strlcat(newopts, o, sizeof (newopts)); - strlcat(newopts, " ", sizeof (newopts)); + strlcat(newopts, o, newopts_len); + strlcat(newopts, " ", newopts_len); } - return (fputs(newopts, out)); + ret = fputs(newopts, out); + free(newopts); + return (ret); } static int @@ -106,20 +107,36 @@ if (strcmp(shareopts, "on") == 0) shareopts = ""; - boolean_t need_free; - char *mp; + boolean_t need_free, fnd_semi; + char *mp, *lineopts, *exportopts, *s; + size_t whitelen; int rc = nfs_escape_mountpoint(impl_share->sa_mountpoint, &mp, &need_free); if (rc != SA_OK) return (rc); - if (fputs(mp, tmpfile) == EOF || - fputc('\t', tmpfile) == EOF || - translate_opts(shareopts, tmpfile) == EOF || - fputc('\n', tmpfile) == EOF) { - fprintf(stderr, "failed to write to temporary file\n"); - rc = SA_SYSTEM_ERR; + lineopts = strdup(shareopts); + s = lineopts; + fnd_semi = B_FALSE; + while ((exportopts = strsep(&s, ";")) != NULL) { + if (s != NULL) + fnd_semi = B_TRUE; + /* Ignore only whitespace between ';' separated option sets. */ + if (fnd_semi) { + whitelen = strspn(exportopts, "\t "); + if (exportopts[whitelen] == '\0') + continue; + } + if (fputs(mp, tmpfile) == EOF || + fputc('\t', tmpfile) == EOF || + translate_opts(exportopts, tmpfile) == EOF || + fputc('\n', tmpfile) == EOF) { + fprintf(stderr, "failed to write to temporary file\n"); + rc = SA_SYSTEM_ERR; + break; + } } + free(lineopts); if (need_free) free(mp); diff --git a/sys/contrib/openzfs/man/man7/zfsprops.7.sav b/sys/contrib/openzfs/man/man7/zfsprops.7 --- a/sys/contrib/openzfs/man/man7/zfsprops.7.sav +++ b/sys/contrib/openzfs/man/man7/zfsprops.7 @@ -38,7 +38,7 @@ .\" Copyright (c) 2019, Kjeld Schouten-Lebbing .\" Copyright (c) 2022 Hewlett Packard Enterprise Development LP. .\" -.Dd August 8, 2023 +.Dd June 29, 2024 .Dt ZFSPROPS 7 .Os . @@ -1726,6 +1726,13 @@ .Xr exports 5 . This is done to negate the need for quoting, as well as to make parsing with scripts easier. +.Pp +For FreeBSD, there may be multiple sets of options separated by semicolon(s). +Each set of options must apply to different hosts or networks and each +set of options will create a separate line for +.Xr exports 5 . +Any semicolon separated option set that consists entirely of whitespace +will be ignored. .Pp See .Xr exports 5