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 http://www.opensolaris.org/os/licensing.
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 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
28 * Copyright 2017 RackTop Systems.
29 * Copyright 2019 Nexenta Systems, Inc.
30 */
31
32 #include <stdio.h>
33 #include <libzfs.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <errno.h>
37 #include <zone.h>
38 #include <libshare.h>
39 #include "libshare_impl.h"
40 #include <libintl.h>
41 #include <sys/mnttab.h>
42 #include <sys/mntent.h>
43 #include <assert.h>
44
45 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
46 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
47 extern char *sa_fstype(char *);
48 extern void set_node_attr(void *, char *, char *);
49 extern int sa_is_share(void *);
50 extern void sa_update_sharetab_ts(sa_handle_t);
51
52 /*
53 * File system specific code for ZFS. The original code was stolen
54 * from the "zfs" command and modified to better suit this library's
55 * usage.
56 */
57
58 typedef struct get_all_cbdata {
59 zfs_handle_t **cb_handles;
60 size_t cb_alloc;
61 size_t cb_used;
62 uint_t cb_types;
63 } get_all_cbdata_t;
64
65 /*
66 * sa_zfs_init(impl_handle)
67 *
68 * Initialize an access handle into libzfs. The handle needs to stay
69 * around until sa_zfs_fini() in order to maintain the cache of
70 * mounts.
71 */
72
73 int
sa_zfs_init(sa_handle_impl_t impl_handle)74 sa_zfs_init(sa_handle_impl_t impl_handle)
75 {
76 impl_handle->zfs_libhandle = libzfs_init();
77 if (impl_handle->zfs_libhandle != NULL) {
78 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
79 return (B_TRUE);
80 }
81 return (B_FALSE);
82 }
83
84 /*
85 * sa_zfs_fini(impl_handle)
86 *
87 * cleanup data structures and the libzfs handle used for accessing
88 * zfs file share info.
89 */
90
91 void
sa_zfs_fini(sa_handle_impl_t impl_handle)92 sa_zfs_fini(sa_handle_impl_t impl_handle)
93 {
94 if (impl_handle->zfs_libhandle != NULL) {
95 if (impl_handle->zfs_list != NULL) {
96 zfs_handle_t **zhp = impl_handle->zfs_list;
97 size_t i;
98
99 /*
100 * Contents of zfs_list need to be freed so we
101 * don't lose ZFS handles.
102 */
103 for (i = 0; i < impl_handle->zfs_list_count; i++) {
104 zfs_close(zhp[i]);
105 }
106 free(impl_handle->zfs_list);
107 impl_handle->zfs_list = NULL;
108 impl_handle->zfs_list_count = 0;
109 }
110
111 libzfs_fini(impl_handle->zfs_libhandle);
112 impl_handle->zfs_libhandle = NULL;
113 }
114 }
115
116 /*
117 * get_one_filesystem(zfs_handle_t, data)
118 *
119 * an iterator function called while iterating through the ZFS
120 * root. It accumulates into an array of file system handles that can
121 * be used to derive info about those file systems.
122 *
123 * Note that as this function is called, we close all zhp handles that
124 * are not going to be places into the cp_handles list. We don't want
125 * to close the ones we are keeping, but all others would be leaked if
126 * not closed here.
127 */
128
129 static int
get_one_filesystem(zfs_handle_t * zhp,void * data)130 get_one_filesystem(zfs_handle_t *zhp, void *data)
131 {
132 get_all_cbdata_t *cbp = data;
133 zfs_type_t type = zfs_get_type(zhp);
134
135 /*
136 * Interate over any nested datasets.
137 */
138 if (type == ZFS_TYPE_FILESYSTEM &&
139 zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) {
140 zfs_close(zhp);
141 return (1);
142 }
143
144 /*
145 * Skip any datasets whose type does not match.
146 */
147 if ((type & cbp->cb_types) == 0) {
148 zfs_close(zhp);
149 return (0);
150 }
151
152 if (cbp->cb_alloc == cbp->cb_used) {
153 zfs_handle_t **handles;
154
155 if (cbp->cb_alloc == 0)
156 cbp->cb_alloc = 64;
157 else
158 cbp->cb_alloc *= 2;
159
160 handles = (zfs_handle_t **)calloc(1,
161 cbp->cb_alloc * sizeof (void *));
162
163 if (handles == NULL) {
164 zfs_close(zhp);
165 return (0);
166 }
167 if (cbp->cb_handles) {
168 bcopy(cbp->cb_handles, handles,
169 cbp->cb_used * sizeof (void *));
170 free(cbp->cb_handles);
171 }
172
173 cbp->cb_handles = handles;
174 }
175
176 cbp->cb_handles[cbp->cb_used++] = zhp;
177
178 return (0);
179 }
180
181 /*
182 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
183 *
184 * iterate through all ZFS file systems starting at the root. Returns
185 * a count and an array of handle pointers. Allocating is only done
186 * once. The caller does not need to free since it will be done at
187 * sa_zfs_fini() time.
188 */
189
190 static void
get_all_filesystems(sa_handle_impl_t impl_handle,zfs_handle_t *** fslist,size_t * count)191 get_all_filesystems(sa_handle_impl_t impl_handle,
192 zfs_handle_t ***fslist, size_t *count)
193 {
194 get_all_cbdata_t cb = { 0 };
195 cb.cb_types = ZFS_TYPE_FILESYSTEM;
196
197 if (impl_handle->zfs_list != NULL) {
198 *fslist = impl_handle->zfs_list;
199 *count = impl_handle->zfs_list_count;
200 return;
201 }
202
203 (void) zfs_iter_root(impl_handle->zfs_libhandle,
204 get_one_filesystem, &cb);
205
206 impl_handle->zfs_list = *fslist = cb.cb_handles;
207 impl_handle->zfs_list_count = *count = cb.cb_used;
208 }
209
210 /*
211 * mountpoint_compare(a, b)
212 *
213 * compares the mountpoint on two zfs file systems handles.
214 * returns values following strcmp() model.
215 */
216
217 static int
mountpoint_compare(const void * a,const void * b)218 mountpoint_compare(const void *a, const void *b)
219 {
220 zfs_handle_t **za = (zfs_handle_t **)a;
221 zfs_handle_t **zb = (zfs_handle_t **)b;
222 char mounta[MAXPATHLEN];
223 char mountb[MAXPATHLEN];
224
225 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
226 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
227 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
228 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
229
230 return (strcmp(mounta, mountb));
231 }
232
233 /*
234 * return legacy mountpoint. Caller provides space for mountpoint and
235 * dataset.
236 */
237 int
get_legacy_mountpoint(const char * path,char * dataset,size_t dlen,char * mountpoint,size_t mlen)238 get_legacy_mountpoint(const char *path, char *dataset, size_t dlen,
239 char *mountpoint, size_t mlen)
240 {
241 FILE *fp;
242 struct mnttab entry;
243 int rc = 1;
244
245 if ((fp = fopen(MNTTAB, "r")) == NULL) {
246 return (1);
247 }
248
249 while (getmntent(fp, &entry) == 0) {
250
251 if (entry.mnt_fstype == NULL ||
252 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
253 continue;
254
255 if (strcmp(entry.mnt_mountp, path) == 0) {
256 if (mlen > 0)
257 (void) strlcpy(mountpoint, entry.mnt_mountp,
258 mlen);
259 if (dlen > 0)
260 (void) strlcpy(dataset, entry.mnt_special,
261 dlen);
262 rc = 0;
263 break;
264 }
265 }
266 (void) fclose(fp);
267 return (rc);
268 }
269
270
271 /*
272 * Verifies that a specific zfs filesystem handle meets the criteria necessary
273 * to be used by libshare operations. See get_zfs_dataset.
274 */
275 static char *
verify_zfs_handle(zfs_handle_t * hdl,const char * path,boolean_t search_mnttab)276 verify_zfs_handle(zfs_handle_t *hdl, const char *path, boolean_t search_mnttab)
277 {
278 char mountpoint[ZFS_MAXPROPLEN];
279 char canmount[ZFS_MAXPROPLEN] = { 0 };
280 /* must have a mountpoint */
281 if (zfs_prop_get(hdl, ZFS_PROP_MOUNTPOINT, mountpoint,
282 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
283 /* no mountpoint */
284 return (NULL);
285 }
286
287 /* mountpoint must be a path */
288 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
289 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
290 /*
291 * Search mmttab for mountpoint and get dataset.
292 */
293
294 if (search_mnttab == B_TRUE &&
295 get_legacy_mountpoint(path, mountpoint,
296 sizeof (mountpoint), NULL, 0) == 0) {
297 return (strdup(mountpoint));
298 }
299 return (NULL);
300 }
301
302 /* canmount must be set */
303 if (zfs_prop_get(hdl, ZFS_PROP_CANMOUNT, canmount,
304 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
305 strcmp(canmount, "off") == 0)
306 return (NULL);
307
308 /*
309 * have a mountable handle but want to skip those marked none
310 * and legacy
311 */
312 if (strcmp(mountpoint, path) == 0) {
313 return (strdup((char *)zfs_get_name(hdl)));
314 }
315
316 return (NULL);
317 }
318
319 /*
320 * get_zfs_dataset(impl_handle, path)
321 *
322 * get the name of the ZFS dataset the path is equivalent to. The
323 * dataset name is used for get/set of ZFS properties since libzfs
324 * requires a dataset to do a zfs_open().
325 */
326
327 static char *
get_zfs_dataset(sa_handle_impl_t impl_handle,char * path,boolean_t search_mnttab)328 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path,
329 boolean_t search_mnttab)
330 {
331 size_t i, count = 0;
332 zfs_handle_t **zlist;
333 char *cutpath;
334 zfs_handle_t *handle_from_path;
335 char *ret = NULL;
336
337 /*
338 * First we optimistically assume that the mount path for the filesystem
339 * is the same as the name of the filesystem (minus some number of
340 * leading slashes). If this is true, then zfs_open should properly open
341 * the filesystem. We duplicate the error checking done later in the
342 * function for consistency. If anything fails, we resort to the
343 * (extremely slow) search of all the filesystems.
344 */
345 cutpath = path + strspn(path, "/");
346
347 assert(impl_handle->zfs_libhandle != NULL);
348 libzfs_print_on_error(impl_handle->zfs_libhandle, B_FALSE);
349 handle_from_path = zfs_open(impl_handle->zfs_libhandle, cutpath,
350 ZFS_TYPE_FILESYSTEM);
351 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
352 if (handle_from_path != NULL) {
353 ret = verify_zfs_handle(handle_from_path, path, search_mnttab);
354 zfs_close(handle_from_path);
355 if (ret != NULL) {
356 return (ret);
357 }
358 }
359 /*
360 * Couldn't find a filesystem optimistically, check all the handles we
361 * can.
362 */
363 get_all_filesystems(impl_handle, &zlist, &count);
364 for (i = 0; i < count; i++) {
365 assert(zlist[i]);
366 if ((ret = verify_zfs_handle(zlist[i], path,
367 search_mnttab)) != NULL)
368 return (ret);
369 }
370
371 /* Couldn't find a matching dataset */
372 return (NULL);
373 }
374
375 /*
376 * get_zfs_property(dataset, property)
377 *
378 * Get the file system property specified from the ZFS dataset.
379 */
380
381 static char *
get_zfs_property(char * dataset,zfs_prop_t property)382 get_zfs_property(char *dataset, zfs_prop_t property)
383 {
384 zfs_handle_t *handle = NULL;
385 char shareopts[ZFS_MAXPROPLEN];
386 libzfs_handle_t *libhandle;
387
388 libhandle = libzfs_init();
389 if (libhandle != NULL) {
390 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM);
391 if (handle != NULL) {
392 if (zfs_prop_get(handle, property, shareopts,
393 sizeof (shareopts), NULL, NULL, 0,
394 B_FALSE) == 0) {
395 zfs_close(handle);
396 libzfs_fini(libhandle);
397 return (strdup(shareopts));
398 }
399 zfs_close(handle);
400 }
401 libzfs_fini(libhandle);
402 }
403 return (NULL);
404 }
405
406 /*
407 * sa_zfs_is_shared(handle, path)
408 *
409 * Check to see if the ZFS path provided has the sharenfs option set
410 * or not.
411 */
412
413 int
sa_zfs_is_shared(sa_handle_t sahandle,char * path)414 sa_zfs_is_shared(sa_handle_t sahandle, char *path)
415 {
416 int ret = 0;
417 char *dataset;
418 zfs_handle_t *handle = NULL;
419 char shareopts[ZFS_MAXPROPLEN];
420 libzfs_handle_t *libhandle;
421
422 dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE);
423 if (dataset != NULL) {
424 libhandle = libzfs_init();
425 if (libhandle != NULL) {
426 handle = zfs_open(libhandle, dataset,
427 ZFS_TYPE_FILESYSTEM);
428 if (handle != NULL) {
429 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS,
430 shareopts, sizeof (shareopts), NULL, NULL,
431 0, B_FALSE) == 0 &&
432 strcmp(shareopts, "off") != 0) {
433 ret = 1; /* it is shared */
434 }
435 zfs_close(handle);
436 }
437 libzfs_fini(libhandle);
438 }
439 free(dataset);
440 }
441 return (ret);
442 }
443
444 /*
445 * find_or_create_group(handle, groupname, proto, *err)
446 *
447 * While walking the ZFS tree, we need to add shares to a defined
448 * group. If the group doesn't exist, create it first, making sure it
449 * is marked as a ZFS group.
450 *
451 * Note that all ZFS shares are in a subgroup of the top level group
452 * called "zfs".
453 */
454
455 static sa_group_t
find_or_create_group(sa_handle_t handle,char * groupname,char * proto,int * err)456 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
457 {
458 sa_group_t group;
459 sa_optionset_t optionset;
460 int ret = SA_OK;
461
462 /*
463 * we check to see if the "zfs" group exists. Since this
464 * should be the top level group, we don't want the
465 * parent. This is to make sure the zfs group has been created
466 * and to created if it hasn't been.
467 */
468 group = sa_get_group(handle, groupname);
469 if (group == NULL) {
470 group = sa_create_group(handle, groupname, &ret);
471
472 /* make sure this is flagged as a ZFS group */
473 if (group != NULL)
474 ret = sa_set_group_attr(group, "zfs", "true");
475 }
476 if (group != NULL) {
477 if (proto != NULL) {
478 optionset = sa_get_optionset(group, proto);
479 if (optionset == NULL)
480 optionset = sa_create_optionset(group, proto);
481 }
482 }
483 if (err != NULL)
484 *err = ret;
485 return (group);
486 }
487
488 /*
489 * find_or_create_zfs_subgroup(groupname, optstring, *err)
490 *
491 * ZFS shares will be in a subgroup of the "zfs" master group. This
492 * function looks to see if the groupname exists and returns it if it
493 * does or else creates a new one with the specified name and returns
494 * that. The "zfs" group will exist before we get here, but we make
495 * sure just in case.
496 *
497 * err must be a valid pointer.
498 */
499
500 static sa_group_t
find_or_create_zfs_subgroup(sa_handle_t handle,char * groupname,char * proto,char * optstring,int * err)501 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
502 char *optstring, int *err)
503 {
504 sa_group_t group = NULL;
505 sa_group_t zfs;
506 char *name;
507 char *options;
508
509 /* start with the top-level "zfs" group */
510 zfs = sa_get_group(handle, "zfs");
511 *err = SA_OK;
512 if (zfs != NULL) {
513 for (group = sa_get_sub_group(zfs); group != NULL;
514 group = sa_get_next_group(group)) {
515 name = sa_get_group_attr(group, "name");
516 if (name != NULL && strcmp(name, groupname) == 0) {
517 /* have the group so break out of here */
518 sa_free_attr_string(name);
519 break;
520 }
521 if (name != NULL)
522 sa_free_attr_string(name);
523 }
524
525 if (group == NULL) {
526 /*
527 * Need to create the sub-group since it doesn't exist
528 */
529 group = _sa_create_zfs_group(zfs, groupname);
530 if (group == NULL) {
531 *err = SA_NO_MEMORY;
532 return (NULL);
533 }
534 set_node_attr(group, "zfs", "true");
535 }
536 if (strcmp(optstring, "on") == 0)
537 optstring = "rw";
538 options = strdup(optstring);
539 if (options != NULL) {
540 *err = sa_parse_legacy_options(group, options,
541 proto);
542 /* If no optionset, add one. */
543 if (sa_get_optionset(group, proto) == NULL)
544 (void) sa_create_optionset(group, proto);
545
546 /*
547 * Do not forget to update an optionset of
548 * the parent group so that it contains
549 * all protocols its subgroups have.
550 */
551 if (sa_get_optionset(zfs, proto) == NULL)
552 (void) sa_create_optionset(zfs, proto);
553
554 free(options);
555 } else {
556 *err = SA_NO_MEMORY;
557 }
558 }
559 return (group);
560 }
561
562 /*
563 * zfs_construct_resource(share, name, base, dataset)
564 *
565 * Add a resource to the share using name as a template. If name ==
566 * NULL, then construct a name based on the dataset value.
567 * name.
568 */
569 static void
zfs_construct_resource(sa_share_t share,char * dataset)570 zfs_construct_resource(sa_share_t share, char *dataset)
571 {
572 char buff[SA_MAX_RESOURCE_NAME + 1];
573 int ret = SA_OK;
574
575 (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
576 sa_fix_resource_name(buff);
577 (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
578 }
579
580 /*
581 * zfs_inherited(handle, source, sourcestr)
582 *
583 * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
584 * for readability.
585 */
586 static int
zfs_inherited(sa_handle_t handle,sa_share_t share,char * sourcestr,char * shareopts,char * mountpoint,char * proto,char * dataset)587 zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
588 char *shareopts, char *mountpoint, char *proto, char *dataset)
589 {
590 int doshopt = 0;
591 int err = SA_OK;
592 sa_group_t group;
593 sa_resource_t resource;
594 uint64_t features;
595
596 /*
597 * Need to find the "real" parent sub-group. It may not be
598 * mounted, but it was identified in the "sourcestr"
599 * variable. The real parent not mounted can occur if
600 * "canmount=off and sharenfs=on".
601 */
602 group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
603 shareopts, &doshopt);
604 if (group != NULL) {
605 /*
606 * We may need the first share for resource
607 * prototype. We only care about it if it has a
608 * resource that sets a prefix value.
609 */
610 if (share == NULL)
611 share = _sa_add_share(group, mountpoint,
612 SA_SHARE_TRANSIENT, &err,
613 (uint64_t)SA_FEATURE_NONE);
614 /*
615 * some options may only be on shares. If the opt
616 * string contains one of those, we put it just on the
617 * share.
618 */
619 if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) {
620 char *options;
621 options = strdup(shareopts);
622 if (options != NULL) {
623 set_node_attr(share, "dataset", dataset);
624 err = sa_parse_legacy_options(share, options,
625 proto);
626 set_node_attr(share, "dataset", NULL);
627 free(options);
628 }
629 if (sa_get_optionset(group, proto) == NULL)
630 (void) sa_create_optionset(group, proto);
631 }
632 features = sa_proto_get_featureset(proto);
633 if (share != NULL && features & SA_FEATURE_RESOURCE) {
634 /*
635 * We have a share and the protocol requires
636 * that at least one resource exist (probably
637 * SMB). We need to make sure that there is at
638 * least one.
639 */
640 resource = sa_get_share_resource(share, NULL);
641 if (resource == NULL) {
642 zfs_construct_resource(share, dataset);
643 }
644 }
645 } else {
646 err = SA_NO_MEMORY;
647 }
648 return (err);
649 }
650
651 /*
652 * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset,
653 * grouperr)
654 *
655 * handle case where this is the top of a sub-group in ZFS. Pulled out
656 * of sa_get_zfs_shares for readability. We need the grouperr from the
657 * creation of the subgroup to know whether to add the public
658 * property, etc. to the specific share.
659 */
660 static int
zfs_notinherited(sa_group_t group,sa_share_t share,char * mountpoint,char * shareopts,char * proto,char * dataset,int grouperr)661 zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
662 char *shareopts, char *proto, char *dataset, int grouperr)
663 {
664 int err = SA_OK;
665 sa_resource_t resource;
666 uint64_t features;
667
668 set_node_attr(group, "zfs", "true");
669 if (share == NULL)
670 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
671 &err, (uint64_t)SA_FEATURE_NONE);
672
673 if (err != SA_OK)
674 return (err);
675
676 if (strcmp(shareopts, "on") == 0)
677 shareopts = "";
678 if (shareopts != NULL) {
679 char *options;
680 if (grouperr == SA_PROP_SHARE_ONLY) {
681 /*
682 * Some properties may only be on shares, but
683 * due to the ZFS sub-groups being artificial,
684 * we sometimes get this and have to deal with
685 * it. We do it by attempting to put it on the
686 * share.
687 */
688 options = strdup(shareopts);
689 if (options != NULL) {
690 err = sa_parse_legacy_options(share,
691 options, proto);
692 free(options);
693 }
694 }
695 /* Unmark the share's changed state */
696 set_node_attr(share, "changed", NULL);
697 }
698 features = sa_proto_get_featureset(proto);
699 if (share != NULL && features & SA_FEATURE_RESOURCE) {
700 /*
701 * We have a share and the protocol requires that at
702 * least one resource exist (probably SMB). We need to
703 * make sure that there is at least one.
704 */
705 resource = sa_get_share_resource(share, NULL);
706 if (resource == NULL) {
707 zfs_construct_resource(share, dataset);
708 }
709 }
710 return (err);
711 }
712
713 /*
714 * zfs_grp_error(err)
715 *
716 * Print group create error, but only once. If err is 0 do the
717 * print else don't.
718 */
719
720 static void
zfs_grp_error(int err)721 zfs_grp_error(int err)
722 {
723 if (err == 0) {
724 /* only print error once */
725 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
726 "Cannot create ZFS subgroup during initialization:"
727 " %s\n"), sa_errorstr(SA_SYSTEM_ERR));
728 }
729 }
730
731 /*
732 * zfs_process_share(handle, share, mountpoint, proto, source,
733 * shareopts, sourcestr)
734 *
735 * Creates the subgroup, if necessary and adds shares, resources
736 * and properties.
737 */
738 int
sa_zfs_process_share(sa_handle_t handle,sa_group_t group,sa_share_t share,char * mountpoint,char * proto,zprop_source_t source,char * shareopts,char * sourcestr,char * dataset)739 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
740 char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
741 char *sourcestr, char *dataset)
742 {
743 int err = SA_OK;
744
745 if (source & ZPROP_SRC_INHERITED) {
746 err = zfs_inherited(handle, share, sourcestr, shareopts,
747 mountpoint, proto, dataset);
748 } else {
749 group = find_or_create_zfs_subgroup(handle, dataset, proto,
750 shareopts, &err);
751 if (group == NULL) {
752 static boolean_t reported_error = B_FALSE;
753 /*
754 * There is a problem, but we can't do
755 * anything about it at this point so we issue
756 * a warning and move on.
757 */
758 zfs_grp_error(reported_error);
759 reported_error = B_TRUE;
760 }
761 set_node_attr(group, "zfs", "true");
762 /*
763 * Add share with local opts via zfs_notinherited.
764 */
765 err = zfs_notinherited(group, share, mountpoint, shareopts,
766 proto, dataset, err);
767 }
768 return (err);
769 }
770
771 /*
772 * Walk the mnttab for all zfs mounts and determine which are
773 * shared. Find or create the appropriate group/sub-group to contain
774 * the shares.
775 *
776 * All shares are in a sub-group that will hold the properties. This
777 * allows representing the inherited property model.
778 *
779 * One area of complication is if "sharenfs" is set at one level of
780 * the directory tree and "sharesmb" is set at a different level, the
781 * a sub-group must be formed at the lower level for both
782 * protocols. That is the nature of the problem in CR 6667349.
783 */
784 static int
sa_get_zfs_share_common(sa_handle_t handle,zfs_handle_t * fs_handle,char * path,sa_group_t zfsgroup)785 sa_get_zfs_share_common(sa_handle_t handle, zfs_handle_t *fs_handle, char *path,
786 sa_group_t zfsgroup)
787 {
788 boolean_t smb, nfs;
789 boolean_t smb_inherited, nfs_inherited;
790 char nfsshareopts[ZFS_MAXPROPLEN];
791 char smbshareopts[ZFS_MAXPROPLEN];
792 char nfssourcestr[ZFS_MAXPROPLEN];
793 char smbsourcestr[ZFS_MAXPROPLEN];
794 char mountpoint[ZFS_MAXPROPLEN];
795 int err = SA_OK;
796 zprop_source_t source;
797 sa_share_t share;
798 char *dataset;
799
800 source = ZPROP_SRC_ALL;
801 /* If no mountpoint, skip. */
802 if (zfs_prop_get(fs_handle, ZFS_PROP_MOUNTPOINT,
803 mountpoint, sizeof (mountpoint), NULL, NULL, 0,
804 B_FALSE) != 0)
805 return (SA_SYSTEM_ERR);
806
807 if (path != NULL)
808 (void) strncpy(path, mountpoint, sizeof (mountpoint));
809 /*
810 * zfs_get_name value must not be freed. It is just a
811 * pointer to a value in the handle.
812 */
813 if ((dataset = (char *)zfs_get_name(fs_handle)) == NULL)
814 return (SA_SYSTEM_ERR);
815
816 /*
817 * only deal with "mounted" file systems since
818 * unmounted file systems can't actually be shared.
819 */
820
821 if (!zfs_is_mounted(fs_handle, NULL))
822 return (SA_SYSTEM_ERR);
823
824 /*
825 * Ignore "zoned" datasets in global zone.
826 */
827 if (getzoneid() == GLOBAL_ZONEID &&
828 zfs_prop_get_int(fs_handle, ZFS_PROP_ZONED))
829 return (SA_SYSTEM_ERR);
830
831 nfs = nfs_inherited = B_FALSE;
832
833 if (zfs_prop_get(fs_handle, ZFS_PROP_SHARENFS, nfsshareopts,
834 sizeof (nfsshareopts), &source, nfssourcestr,
835 ZFS_MAXPROPLEN, B_FALSE) == 0 &&
836 strcmp(nfsshareopts, "off") != 0) {
837 if (source & ZPROP_SRC_INHERITED)
838 nfs_inherited = B_TRUE;
839 else
840 nfs = B_TRUE;
841 }
842
843 smb = smb_inherited = B_FALSE;
844 if (zfs_prop_get(fs_handle, ZFS_PROP_SHARESMB, smbshareopts,
845 sizeof (smbshareopts), &source, smbsourcestr,
846 ZFS_MAXPROPLEN, B_FALSE) == 0 &&
847 strcmp(smbshareopts, "off") != 0) {
848 if (source & ZPROP_SRC_INHERITED)
849 smb_inherited = B_TRUE;
850 else
851 smb = B_TRUE;
852 }
853
854 /*
855 * If the mountpoint is already shared, it must be a
856 * non-ZFS share. We want to remove the share from its
857 * parent group and reshare it under ZFS.
858 */
859 share = sa_find_share(handle, mountpoint);
860 if (share != NULL &&
861 (nfs || smb || nfs_inherited || smb_inherited)) {
862 err = sa_remove_share(share);
863 share = NULL;
864 }
865
866 /*
867 * At this point, we have the information needed to
868 * determine what to do with the share.
869 *
870 * If smb or nfs is set, we have a new sub-group.
871 * If smb_inherit and/or nfs_inherit is set, then
872 * place on an existing sub-group. If both are set,
873 * the existing sub-group is the closest up the tree.
874 */
875 if (nfs || smb) {
876 /*
877 * Non-inherited is the straightforward
878 * case. sa_zfs_process_share handles it
879 * directly. Make sure that if the "other"
880 * protocol is inherited, that we treat it as
881 * non-inherited as well.
882 */
883 if (nfs || nfs_inherited) {
884 err = sa_zfs_process_share(handle, zfsgroup,
885 share, mountpoint, "nfs",
886 0, nfsshareopts,
887 nfssourcestr, dataset);
888 share = sa_find_share(handle, mountpoint);
889 }
890 if (smb || smb_inherited) {
891 err = sa_zfs_process_share(handle, zfsgroup,
892 share, mountpoint, "smb",
893 0, smbshareopts,
894 smbsourcestr, dataset);
895 }
896 } else if (nfs_inherited || smb_inherited) {
897 char *grpdataset;
898 /*
899 * If we only have inherited groups, it is
900 * important to find the closer of the two if
901 * the protocols are set at different
902 * levels. The closest sub-group is the one we
903 * want to work with.
904 */
905 if (nfs_inherited && smb_inherited) {
906 if (strcmp(nfssourcestr, smbsourcestr) <= 0)
907 grpdataset = nfssourcestr;
908 else
909 grpdataset = smbsourcestr;
910 } else if (nfs_inherited) {
911 grpdataset = nfssourcestr;
912 } else if (smb_inherited) {
913 grpdataset = smbsourcestr;
914 }
915 if (nfs_inherited) {
916 err = sa_zfs_process_share(handle, zfsgroup,
917 share, mountpoint, "nfs",
918 ZPROP_SRC_INHERITED, nfsshareopts,
919 grpdataset, dataset);
920 share = sa_find_share(handle, mountpoint);
921 }
922 if (smb_inherited) {
923 err = sa_zfs_process_share(handle, zfsgroup,
924 share, mountpoint, "smb",
925 ZPROP_SRC_INHERITED, smbshareopts,
926 grpdataset, dataset);
927 }
928 }
929 return (err);
930 }
931
932 /*
933 * Handles preparing generic objects such as the libzfs handle and group for
934 * sa_get_one_zfs_share, sa_get_zfs_share_for_name, and sa_get_zfs_shares.
935 */
936 static int
prep_zfs_handle_and_group(sa_handle_t handle,char * groupname,libzfs_handle_t ** zfs_libhandle,sa_group_t * zfsgroup,int * err)937 prep_zfs_handle_and_group(sa_handle_t handle, char *groupname,
938 libzfs_handle_t **zfs_libhandle, sa_group_t *zfsgroup, int *err)
939 {
940 /*
941 * If we can't access libzfs, don't bother doing anything.
942 */
943 *zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
944 if (*zfs_libhandle == NULL)
945 return (SA_SYSTEM_ERR);
946
947 *zfsgroup = find_or_create_group(handle, groupname, NULL, err);
948 return (SA_OK);
949 }
950
951 /*
952 * The O.G. zfs share preparation function. This initializes all zfs shares for
953 * use with libshare.
954 */
955 int
sa_get_zfs_shares(sa_handle_t handle,char * groupname)956 sa_get_zfs_shares(sa_handle_t handle, char *groupname)
957 {
958 sa_group_t zfsgroup;
959 zfs_handle_t **zlist;
960 size_t count = 0;
961 libzfs_handle_t *zfs_libhandle;
962 int err;
963
964 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
965 &zfsgroup, &err)) != SA_OK) {
966 return (err);
967 }
968 /* Not an error, this could be a legacy condition */
969 if (zfsgroup == NULL)
970 return (SA_OK);
971
972 /*
973 * need to walk the mounted ZFS pools and datasets to
974 * find shares that are possible.
975 */
976 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
977 qsort(zlist, count, sizeof (void *), mountpoint_compare);
978
979 for (int i = 0; i < count; i++) {
980 err = sa_get_zfs_share_common(handle, zlist[i], NULL, zfsgroup);
981 }
982 /*
983 * Don't need to free the "zlist" variable since it is only a
984 * pointer to a cached value that will be freed when
985 * sa_fini() is called.
986 */
987 return (err);
988 }
989
990 /*
991 * Initializes shares for only the dataset specified fs_handle.
992 * This is used as a performance optimization relative to sa_get_zfs_shares.
993 */
994 int
sa_get_zfs_share(sa_handle_t handle,char * groupname,zfs_handle_t * fs_handle)995 sa_get_zfs_share(sa_handle_t handle, char *groupname, zfs_handle_t *fs_handle)
996 {
997 sa_group_t zfsgroup;
998 libzfs_handle_t *zfs_libhandle;
999 int err;
1000
1001 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1002 &zfsgroup, &err)) != SA_OK) {
1003 return (err);
1004 }
1005 /* Not an error, this could be a legacy condition */
1006 if (zfsgroup == NULL)
1007 return (SA_OK);
1008
1009 err = sa_get_zfs_share_common(handle, fs_handle, NULL, zfsgroup);
1010 return (err);
1011 }
1012
1013 /*
1014 * Initializes only the handles specified in the sharearg for use with libshare.
1015 * This is used as a performance optimization relative to sa_get_zfs_shares.
1016 */
1017 int
sa_get_one_zfs_share(sa_handle_t handle,char * groupname,sa_init_selective_arg_t * sharearg,char *** paths,size_t * paths_len)1018 sa_get_one_zfs_share(sa_handle_t handle, char *groupname,
1019 sa_init_selective_arg_t *sharearg, char ***paths, size_t *paths_len)
1020 {
1021 sa_group_t zfsgroup;
1022 libzfs_handle_t *zfs_libhandle;
1023 int err;
1024
1025 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1026 &zfsgroup, &err)) != SA_OK) {
1027 return (err);
1028 }
1029 /* Not an error, this could be a legacy condition */
1030 if (zfsgroup == NULL)
1031 return (SA_OK);
1032
1033 *paths_len = sharearg->zhandle_len;
1034 *paths = calloc(*paths_len, sizeof (char *));
1035 for (int i = 0; i < sharearg->zhandle_len; ++i) {
1036 zfs_handle_t *fs_handle =
1037 ((zfs_handle_t **)(sharearg->zhandle_arr))[i];
1038 if (fs_handle == NULL) {
1039 /* Free non-null elements of the paths array */
1040 for (int free_idx = 0; free_idx < *paths_len;
1041 ++free_idx) {
1042 if ((*paths)[free_idx] != NULL)
1043 free((*paths)[free_idx]);
1044 }
1045 free(*paths);
1046 *paths = NULL;
1047 *paths_len = 0;
1048 return (SA_SYSTEM_ERR);
1049 }
1050 (*paths)[i] = malloc(sizeof (char) * ZFS_MAXPROPLEN);
1051 err |= sa_get_zfs_share_common(handle, fs_handle, (*paths)[i],
1052 zfsgroup);
1053 }
1054
1055 return (err);
1056 }
1057
1058 /*
1059 * Initializes only the share with the specified sharename for use with
1060 * libshare.
1061 */
1062 int
sa_get_zfs_share_for_name(sa_handle_t handle,char * groupname,const char * sharename,char * outpath)1063 sa_get_zfs_share_for_name(sa_handle_t handle, char *groupname,
1064 const char *sharename, char *outpath)
1065 {
1066 sa_group_t zfsgroup;
1067 libzfs_handle_t *zfs_libhandle;
1068 int err;
1069
1070 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1071 &zfsgroup, &err)) != SA_OK) {
1072 return (err);
1073 }
1074 /* Not an error, this could be a legacy condition */
1075 if (zfsgroup == NULL)
1076 return (SA_OK);
1077
1078 zfs_handle_t *fs_handle = zfs_open(zfs_libhandle,
1079 sharename + strspn(sharename, "/"), ZFS_TYPE_DATASET);
1080 if (fs_handle == NULL)
1081 return (SA_SYSTEM_ERR);
1082
1083 err = sa_get_zfs_share_common(handle, fs_handle, outpath, zfsgroup);
1084 zfs_close(fs_handle);
1085 return (err);
1086 }
1087
1088
1089
1090 #define COMMAND "/usr/sbin/zfs"
1091
1092 /*
1093 * sa_zfs_set_sharenfs(group, path, on)
1094 *
1095 * Update the "sharenfs" property on the path. If on is true, then set
1096 * to the properties on the group or "on" if no properties are
1097 * defined. Set to "off" if on is false.
1098 */
1099
1100 int
sa_zfs_set_sharenfs(sa_group_t group,char * path,int on)1101 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
1102 {
1103 int ret = SA_NOT_IMPLEMENTED;
1104 char *command;
1105
1106 command = malloc(ZFS_MAXPROPLEN * 2);
1107 if (command != NULL) {
1108 char *opts = NULL;
1109 char *dataset = NULL;
1110 FILE *pfile;
1111 sa_handle_impl_t impl_handle;
1112 /* for now, NFS is always available for "zfs" */
1113 if (on) {
1114 opts = sa_proto_legacy_format("nfs", group, 1);
1115 if (opts != NULL && strlen(opts) == 0) {
1116 free(opts);
1117 opts = strdup("on");
1118 }
1119 }
1120
1121 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1122 assert(impl_handle != NULL);
1123 if (impl_handle != NULL)
1124 dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
1125 else
1126 ret = SA_SYSTEM_ERR;
1127
1128 if (dataset != NULL) {
1129 (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1130 "%s set sharenfs=\"%s\" %s", COMMAND,
1131 opts != NULL ? opts : "off", dataset);
1132 pfile = popen(command, "r");
1133 if (pfile != NULL) {
1134 ret = pclose(pfile);
1135 if (ret != 0)
1136 ret = SA_SYSTEM_ERR;
1137 }
1138 }
1139 if (opts != NULL)
1140 free(opts);
1141 if (dataset != NULL)
1142 free(dataset);
1143 free(command);
1144 }
1145 return (ret);
1146 }
1147
1148 /*
1149 * add_resources(share, opt)
1150 *
1151 * Add resource properties to those in "opt". Resources are prefixed
1152 * with name=resourcename.
1153 */
1154 static char *
add_resources(sa_share_t share,char * opt)1155 add_resources(sa_share_t share, char *opt)
1156 {
1157 char *newopt = NULL;
1158 char *propstr;
1159 sa_resource_t resource;
1160
1161 newopt = strdup(opt);
1162 if (newopt == NULL)
1163 return (newopt);
1164
1165 for (resource = sa_get_share_resource(share, NULL);
1166 resource != NULL;
1167 resource = sa_get_next_resource(resource)) {
1168 char *name;
1169 size_t size;
1170
1171 name = sa_get_resource_attr(resource, "name");
1172 if (name == NULL) {
1173 free(newopt);
1174 return (NULL);
1175 }
1176 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
1177 newopt = calloc(1, size);
1178 if (newopt != NULL)
1179 (void) snprintf(newopt, size, "%s,name=%s", opt, name);
1180 sa_free_attr_string(name);
1181 free(opt);
1182 opt = newopt;
1183 propstr = sa_proto_legacy_format("smb", resource, 0);
1184 if (propstr == NULL) {
1185 free(opt);
1186 return (NULL);
1187 }
1188 size = strlen(propstr) + strlen(opt) + 2;
1189 newopt = calloc(1, size);
1190 if (newopt != NULL)
1191 (void) snprintf(newopt, size, "%s,%s", opt, propstr);
1192 free(opt);
1193 opt = newopt;
1194 }
1195 return (opt);
1196 }
1197
1198 /*
1199 * sa_zfs_set_sharesmb(group, path, on)
1200 *
1201 * Update the "sharesmb" property on the path. If on is true, then set
1202 * to the properties on the group or "on" if no properties are
1203 * defined. Set to "off" if on is false.
1204 */
1205
1206 int
sa_zfs_set_sharesmb(sa_group_t group,char * path,int on)1207 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
1208 {
1209 int ret = SA_NOT_IMPLEMENTED;
1210 char *command;
1211 sa_share_t share;
1212
1213 /* In case SMB not enabled */
1214 if (sa_get_optionset(group, "smb") == NULL)
1215 return (SA_NOT_SUPPORTED);
1216
1217 command = malloc(ZFS_MAXPROPLEN * 2);
1218 if (command != NULL) {
1219 char *opts = NULL;
1220 char *dataset = NULL;
1221 FILE *pfile;
1222 sa_handle_impl_t impl_handle;
1223
1224 if (on) {
1225 char *newopt;
1226
1227 share = sa_get_share(group, NULL);
1228 opts = sa_proto_legacy_format("smb", share, 1);
1229 if (opts != NULL && strlen(opts) == 0) {
1230 free(opts);
1231 opts = strdup("on");
1232 }
1233 newopt = add_resources(opts, share);
1234 free(opts);
1235 opts = newopt;
1236 }
1237
1238 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1239 assert(impl_handle != NULL);
1240 if (impl_handle != NULL)
1241 dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
1242 else
1243 ret = SA_SYSTEM_ERR;
1244
1245 if (dataset != NULL) {
1246 (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1247 "echo %s set sharesmb=\"%s\" %s", COMMAND,
1248 opts != NULL ? opts : "off", dataset);
1249 pfile = popen(command, "r");
1250 if (pfile != NULL) {
1251 ret = pclose(pfile);
1252 if (ret != 0)
1253 ret = SA_SYSTEM_ERR;
1254 }
1255 }
1256 if (opts != NULL)
1257 free(opts);
1258 if (dataset != NULL)
1259 free(dataset);
1260 free(command);
1261 }
1262 return (ret);
1263 }
1264
1265 /*
1266 * sa_zfs_update(group)
1267 *
1268 * call back to ZFS to update the share if necessary.
1269 * Don't do it if it isn't a real change.
1270 */
1271 int
sa_zfs_update(sa_group_t group)1272 sa_zfs_update(sa_group_t group)
1273 {
1274 sa_optionset_t protopt;
1275 sa_group_t parent;
1276 char *command;
1277 char *optstring;
1278 int ret = SA_OK;
1279 int doupdate = 0;
1280 FILE *pfile;
1281
1282 if (sa_is_share(group))
1283 parent = sa_get_parent_group(group);
1284 else
1285 parent = group;
1286
1287 if (parent != NULL) {
1288 command = malloc(ZFS_MAXPROPLEN * 2);
1289 if (command == NULL)
1290 return (SA_NO_MEMORY);
1291
1292 *command = '\0';
1293 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL;
1294 protopt = sa_get_next_optionset(protopt)) {
1295
1296 char *proto = sa_get_optionset_attr(protopt, "type");
1297 char *path;
1298 char *dataset = NULL;
1299 char *zfsopts = NULL;
1300
1301 if (sa_is_share(group)) {
1302 path = sa_get_share_attr((sa_share_t)group,
1303 "path");
1304 if (path != NULL) {
1305 sa_handle_impl_t impl_handle;
1306
1307 impl_handle = sa_find_group_handle(
1308 group);
1309 if (impl_handle != NULL)
1310 dataset = get_zfs_dataset(
1311 impl_handle, path, B_FALSE);
1312 else
1313 ret = SA_SYSTEM_ERR;
1314
1315 sa_free_attr_string(path);
1316 }
1317 } else {
1318 dataset = sa_get_group_attr(group, "name");
1319 }
1320 /* update only when there is an optstring found */
1321 doupdate = 0;
1322 if (proto != NULL && dataset != NULL) {
1323 optstring = sa_proto_legacy_format(proto,
1324 group, 1);
1325 zfsopts = get_zfs_property(dataset,
1326 ZFS_PROP_SHARENFS);
1327
1328 if (optstring != NULL && zfsopts != NULL) {
1329 if (strcmp(optstring, zfsopts) != 0)
1330 doupdate++;
1331 }
1332 if (doupdate) {
1333 if (optstring != NULL &&
1334 strlen(optstring) > 0) {
1335 (void) snprintf(command,
1336 ZFS_MAXPROPLEN * 2,
1337 "%s set share%s=%s %s",
1338 COMMAND, proto,
1339 optstring, dataset);
1340 } else {
1341 (void) snprintf(command,
1342 ZFS_MAXPROPLEN * 2,
1343 "%s set share%s=on %s",
1344 COMMAND, proto,
1345 dataset);
1346 }
1347 pfile = popen(command, "r");
1348 if (pfile != NULL)
1349 ret = pclose(pfile);
1350 switch (ret) {
1351 default:
1352 case 1:
1353 ret = SA_SYSTEM_ERR;
1354 break;
1355 case 2:
1356 ret = SA_SYNTAX_ERR;
1357 break;
1358 case 0:
1359 break;
1360 }
1361 }
1362 if (optstring != NULL)
1363 free(optstring);
1364 if (zfsopts != NULL)
1365 free(zfsopts);
1366 }
1367 if (proto != NULL)
1368 sa_free_attr_string(proto);
1369 if (dataset != NULL)
1370 free(dataset);
1371 }
1372 free(command);
1373 }
1374 return (ret);
1375 }
1376
1377 /*
1378 * sa_group_is_zfs(group)
1379 *
1380 * Given the group, determine if the zfs attribute is set.
1381 */
1382
1383 int
sa_group_is_zfs(sa_group_t group)1384 sa_group_is_zfs(sa_group_t group)
1385 {
1386 char *zfs;
1387 int ret = 0;
1388
1389 zfs = sa_get_group_attr(group, "zfs");
1390 if (zfs != NULL) {
1391 ret = 1;
1392 sa_free_attr_string(zfs);
1393 }
1394 return (ret);
1395 }
1396
1397 /*
1398 * sa_path_is_zfs(path)
1399 *
1400 * Check to see if the file system path represents is of type "zfs".
1401 */
1402
1403 int
sa_path_is_zfs(char * path)1404 sa_path_is_zfs(char *path)
1405 {
1406 char *fstype;
1407 int ret = 0;
1408
1409 fstype = sa_fstype(path);
1410 if (fstype != NULL && strcmp(fstype, "zfs") == 0)
1411 ret = 1;
1412 if (fstype != NULL)
1413 sa_free_fstype(fstype);
1414 return (ret);
1415 }
1416
1417 int
sa_sharetab_fill_zfs(sa_share_t share,share_t * sh,char * proto)1418 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
1419 {
1420 char *path;
1421
1422 /* Make sure path is valid */
1423
1424 path = sa_get_share_attr(share, "path");
1425 if (path != NULL) {
1426 (void) memset(sh, 0, sizeof (sh));
1427 (void) sa_fillshare(share, proto, sh);
1428 sa_free_attr_string(path);
1429 return (0);
1430 } else
1431 return (1);
1432 }
1433
1434 #define SMAX(i, j) \
1435 if ((j) > (i)) { \
1436 (i) = (j); \
1437 }
1438
1439 int
sa_share_zfs(sa_share_t share,sa_resource_t resource,char * path,share_t * sh,void * exportdata,zfs_share_op_t operation)1440 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh,
1441 void *exportdata, zfs_share_op_t operation)
1442 {
1443 libzfs_handle_t *libhandle;
1444 sa_group_t group;
1445 sa_handle_t sahandle;
1446 char *dataset;
1447 int err = EINVAL;
1448 int i, j;
1449 char newpath[MAXPATHLEN];
1450 char *pathp;
1451
1452 /*
1453 * First find the dataset name
1454 */
1455 if ((group = sa_get_parent_group(share)) == NULL) {
1456 return (EINVAL);
1457 }
1458 if ((sahandle = sa_find_group_handle(group)) == NULL) {
1459 return (EINVAL);
1460 }
1461
1462 /*
1463 * If get_zfs_dataset fails, see if it is a subdirectory
1464 */
1465
1466 pathp = path;
1467 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) {
1468 char *p;
1469
1470 if (pathp == path) {
1471 (void) strlcpy(newpath, path, sizeof (newpath));
1472 pathp = newpath;
1473 }
1474
1475 /*
1476 * Make sure only one leading '/' This condition came
1477 * about when using HAStoragePlus which insisted on
1478 * putting an extra leading '/' in the ZFS path
1479 * name. The problem is fixed in other areas, but this
1480 * will catch any other ways that a double slash might
1481 * get introduced.
1482 */
1483 while (*pathp == '/' && *(pathp + 1) == '/')
1484 pathp++;
1485
1486 /*
1487 * chop off part of path, but if we are at root then
1488 * make sure path is a /
1489 */
1490 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) {
1491 if (pathp == p) {
1492 *(p + 1) = '\0'; /* skip over /, root case */
1493 } else {
1494 *p = '\0';
1495 }
1496 } else {
1497 return (EINVAL);
1498 }
1499 }
1500
1501 libhandle = libzfs_init();
1502 if (libhandle != NULL) {
1503 char *resource_name;
1504
1505 i = (sh->sh_path ? strlen(sh->sh_path) : 0);
1506 sh->sh_size = i;
1507
1508 j = (sh->sh_res ? strlen(sh->sh_res) : 0);
1509 sh->sh_size += j;
1510 SMAX(i, j);
1511
1512 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
1513 sh->sh_size += j;
1514 SMAX(i, j);
1515
1516 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
1517 sh->sh_size += j;
1518 SMAX(i, j);
1519
1520 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
1521 sh->sh_size += j;
1522 SMAX(i, j);
1523
1524 resource_name = sa_get_resource_attr(resource, "name");
1525
1526 err = zfs_deleg_share_nfs(libhandle, dataset, path,
1527 resource_name, exportdata, sh, i, operation);
1528 if (err == SA_OK)
1529 sa_update_sharetab_ts(sahandle);
1530 else
1531 err = errno;
1532 if (resource_name)
1533 sa_free_attr_string(resource_name);
1534
1535 libzfs_fini(libhandle);
1536 }
1537 free(dataset);
1538 return (err);
1539 }
1540
1541 /*
1542 * sa_get_zfs_handle(handle)
1543 *
1544 * Given an sa_handle_t, return the libzfs_handle_t *. This is only
1545 * used internally by libzfs. Needed in order to avoid including
1546 * libshare_impl.h in libzfs.
1547 */
1548
1549 libzfs_handle_t *
sa_get_zfs_handle(sa_handle_t handle)1550 sa_get_zfs_handle(sa_handle_t handle)
1551 {
1552 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
1553
1554 return (implhandle->zfs_libhandle);
1555 }
1556
1557 /*
1558 * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
1559 *
1560 * Find the ZFS dataset and mountpoint for a given path
1561 */
1562 int
sa_zfs_get_info(libzfs_handle_t * libzfs,char * path,char * mountpointp,char * datasetp)1563 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp,
1564 char *datasetp)
1565 {
1566 get_all_cbdata_t cb = { 0 };
1567 int i;
1568 char mountpoint[ZFS_MAXPROPLEN];
1569 char dataset[ZFS_MAXPROPLEN];
1570 char canmount[ZFS_MAXPROPLEN];
1571 char *dp;
1572 int count;
1573 int ret = 0;
1574
1575 cb.cb_types = ZFS_TYPE_FILESYSTEM;
1576
1577 if (libzfs == NULL)
1578 return (0);
1579
1580 (void) zfs_iter_root(libzfs, get_one_filesystem, &cb);
1581 count = cb.cb_used;
1582
1583 qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare);
1584 for (i = 0; i < count; i++) {
1585 /* must have a mountpoint */
1586 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT,
1587 mountpoint, sizeof (mountpoint),
1588 NULL, NULL, 0, B_FALSE) != 0) {
1589 /* no mountpoint */
1590 continue;
1591 }
1592
1593 /* mountpoint must be a path */
1594 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
1595 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1596 /*
1597 * Search mmttab for mountpoint
1598 */
1599
1600 if (get_legacy_mountpoint(path, dataset,
1601 ZFS_MAXPROPLEN, mountpoint,
1602 ZFS_MAXPROPLEN) == 0) {
1603 ret = 1;
1604 break;
1605 }
1606 continue;
1607 }
1608
1609 /* canmount must be set */
1610 canmount[0] = '\0';
1611 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount,
1612 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
1613 strcmp(canmount, "off") == 0)
1614 continue;
1615
1616 /*
1617 * have a mountable handle but want to skip those marked none
1618 * and legacy
1619 */
1620 if (strcmp(mountpoint, path) == 0) {
1621 dp = (char *)zfs_get_name(cb.cb_handles[i]);
1622 if (dp != NULL) {
1623 if (datasetp != NULL)
1624 (void) strcpy(datasetp, dp);
1625 if (mountpointp != NULL)
1626 (void) strcpy(mountpointp, mountpoint);
1627 ret = 1;
1628 }
1629 break;
1630 }
1631
1632 }
1633
1634 return (ret);
1635 }
1636
1637 /*
1638 * This method builds values for "sharesmb" property from the
1639 * nvlist argument. The values are returned in sharesmb_val variable.
1640 */
1641 static int
sa_zfs_sprintf_new_prop(nvlist_t * nvl,char * sharesmb_val)1642 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val)
1643 {
1644 char cur_val[MAXPATHLEN];
1645 char *name, *val;
1646 nvpair_t *cur;
1647 int err = 0;
1648
1649 cur = nvlist_next_nvpair(nvl, NULL);
1650 while (cur != NULL) {
1651 name = nvpair_name(cur);
1652 err = nvpair_value_string(cur, &val);
1653 if ((err != 0) || (name == NULL) || (val == NULL))
1654 return (-1);
1655
1656 (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val);
1657 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1658
1659 cur = nvlist_next_nvpair(nvl, cur);
1660 }
1661
1662 return (0);
1663 }
1664
1665 /*
1666 * This method builds values for "sharesmb" property from values
1667 * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1668 * method are passed in sharesmb_val. If a existing property is already
1669 * set via sa_zfs_sprint_new_prop method, then they are not appended
1670 * to the sharesmb_val string. The returned sharesmb_val string is a combination
1671 * of new and existing values for 'sharesmb' property.
1672 */
1673 static int
sa_zfs_sprintf_existing_prop(zfs_handle_t * handle,char * sharesmb_val)1674 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val)
1675 {
1676 char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN];
1677 char *token, *last, *value;
1678
1679 if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts,
1680 sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0)
1681 return (-1);
1682
1683 if (strstr(shareopts, "=") == NULL)
1684 return (0);
1685
1686 for (token = strtok_r(shareopts, ",", &last); token != NULL;
1687 token = strtok_r(NULL, ",", &last)) {
1688 value = strchr(token, '=');
1689 if (value == NULL)
1690 return (-1);
1691 *value++ = '\0';
1692
1693 (void) snprintf(cur_val, MAXPATHLEN, "%s=", token);
1694 if (strstr(sharesmb_val, cur_val) == NULL) {
1695 (void) strlcat(cur_val, value, MAXPATHLEN);
1696 (void) strlcat(cur_val, ",", MAXPATHLEN);
1697 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1698 }
1699 }
1700
1701 return (0);
1702 }
1703
1704 /*
1705 * Sets the share properties on a ZFS share. For now, this method sets only
1706 * the "sharesmb" property.
1707 *
1708 * This method includes building a comma seperated name-value string to be
1709 * set on the "sharesmb" property of a ZFS share. This name-value string is
1710 * build in 2 steps:
1711 * - New property values given as name-value pair are set first.
1712 * - Existing optionset properties, which are not part of the new properties
1713 * passed in step 1, are appended to the newly set properties.
1714 */
1715 int
sa_zfs_setprop(sa_handle_t handle,char * path,nvlist_t * nvl)1716 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl)
1717 {
1718 zfs_handle_t *z_fs;
1719 libzfs_handle_t *z_lib;
1720 char sharesmb_val[MAXPATHLEN];
1721 char *dataset, *lastcomma;
1722
1723 if (nvlist_empty(nvl))
1724 return (0);
1725
1726 if ((handle == NULL) || (path == NULL))
1727 return (-1);
1728
1729 if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL)
1730 return (-1);
1731
1732 if ((z_lib = libzfs_init()) == NULL) {
1733 free(dataset);
1734 return (-1);
1735 }
1736
1737 z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET);
1738 if (z_fs == NULL) {
1739 free(dataset);
1740 libzfs_fini(z_lib);
1741 return (-1);
1742 }
1743
1744 bzero(sharesmb_val, MAXPATHLEN);
1745 if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) {
1746 free(dataset);
1747 zfs_close(z_fs);
1748 libzfs_fini(z_lib);
1749 return (-1);
1750 }
1751
1752 if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) {
1753 free(dataset);
1754 zfs_close(z_fs);
1755 libzfs_fini(z_lib);
1756 return (-1);
1757 }
1758
1759 lastcomma = strrchr(sharesmb_val, ',');
1760 if ((lastcomma != NULL) && (lastcomma[1] == '\0'))
1761 *lastcomma = '\0';
1762
1763 (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB),
1764 sharesmb_val);
1765 free(dataset);
1766 zfs_close(z_fs);
1767 libzfs_fini(z_lib);
1768
1769 return (0);
1770 }
1771