Add -p switch to "zpool get"
[zfs.git] / lib / libshare / libshare.c
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) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011 Gunnar Beutner
25  */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <strings.h>
31 #include <libintl.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <libzfs.h>
36 #include <libshare.h>
37 #include "libshare_impl.h"
38 #include "nfs.h"
39 #include "smb.h"
40
41 static sa_share_impl_t find_share(sa_handle_impl_t handle,
42     const char *sharepath);
43 static sa_share_impl_t alloc_share(const char *sharepath);
44 static void free_share(sa_share_impl_t share);
45
46 static void parse_sharetab(sa_handle_impl_t impl_handle);
47 static int process_share(sa_handle_impl_t impl_handle,
48     sa_share_impl_t impl_share, char *pathname, char *resource,
49     char *fstype, char *options, char *description,
50     char *dataset, boolean_t from_sharetab);
51 static void update_sharetab(sa_handle_impl_t impl_handle);
52
53 static int update_zfs_share(sa_share_impl_t impl_handle, const char *proto);
54 static int update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto);
55
56 static int fstypes_count;
57 static sa_fstype_t *fstypes;
58
59 sa_fstype_t *
60 register_fstype(const char *name, const sa_share_ops_t *ops)
61 {
62         sa_fstype_t *fstype;
63
64         fstype = calloc(sizeof (sa_fstype_t), 1);
65
66         if (fstype == NULL)
67                 return NULL;
68
69         fstype->name = name;
70         fstype->ops = ops;
71         fstype->fsinfo_index = fstypes_count;
72
73         fstypes_count++;
74
75         fstype->next = fstypes;
76         fstypes = fstype;
77
78         return fstype;
79 }
80
81 sa_handle_t
82 sa_init(int init_service)
83 {
84         sa_handle_impl_t impl_handle;
85
86         impl_handle = calloc(sizeof (struct sa_handle_impl), 1);
87
88         if (impl_handle == NULL)
89                 return NULL;
90
91         impl_handle->zfs_libhandle = libzfs_init();
92
93         if (impl_handle->zfs_libhandle != NULL) {
94                 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
95         }
96
97         parse_sharetab(impl_handle);
98         update_zfs_shares(impl_handle, NULL);
99
100         return ((sa_handle_t)impl_handle);
101 }
102
103 __attribute__((constructor)) static void
104 libshare_init(void)
105 {
106         libshare_nfs_init();
107         libshare_smb_init();
108
109         /*
110          * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a
111          * chance to read that file; this is necessary because the sharetab file
112          * might be out of sync with the NFS kernel exports (e.g. due to reboots
113          * or users manually removing shares)
114          */
115         sa_fini(sa_init(0));
116 }
117
118 static void
119 parse_sharetab(sa_handle_impl_t impl_handle) {
120         FILE *fp;
121         char line[512];
122         char *eol, *pathname, *resource, *fstype, *options, *description;
123
124         fp = fopen("/etc/dfs/sharetab", "r");
125
126         if (fp == NULL)
127                 return;
128
129         while (fgets(line, sizeof (line), fp) != NULL) {
130                 eol = line + strlen(line) - 1;
131
132                 while (eol >= line) {
133                         if (*eol != '\r' && *eol != '\n')
134                                 break;
135
136                         *eol = '\0';
137                         eol--;
138                 }
139
140                 pathname = line;
141
142                 if ((resource = strchr(pathname, '\t')) == NULL)
143                         continue;
144
145                 *resource = '\0';
146                 resource++;
147
148                 if ((fstype = strchr(resource, '\t')) == NULL)
149                         continue;
150
151                 *fstype = '\0';
152                 fstype++;
153
154                 if ((options = strchr(fstype, '\t')) == NULL)
155                         continue;
156
157                 *options = '\0';
158                 options++;
159
160                 if ((description = strchr(fstype, '\t')) != NULL) {
161                         *description = '\0';
162                         description++;
163                 }
164
165                 if (strcmp(resource, "-") == 0)
166                         resource = NULL;
167
168                 (void) process_share(impl_handle, NULL, pathname, resource,
169                     fstype, options, description, NULL, B_TRUE);
170         }
171
172         fclose(fp);
173 }
174
175 static void
176 update_sharetab(sa_handle_impl_t impl_handle)
177 {
178         sa_share_impl_t impl_share;
179         int temp_fd;
180         FILE *temp_fp;
181         char tempfile[] = "/etc/dfs/sharetab.XXXXXX";
182         sa_fstype_t *fstype;
183         const char *resource;
184
185         if (mkdir("/etc/dfs", 0755) < 0 && errno != EEXIST) {
186                 return;
187         }
188
189         temp_fd = mkstemp(tempfile);
190
191         if (temp_fd < 0)
192                 return;
193
194         temp_fp = fdopen(temp_fd, "w");
195
196         if (temp_fp == NULL)
197                 return;
198
199         impl_share = impl_handle->shares;
200         while (impl_share != NULL) {
201                 fstype = fstypes;
202                 while (fstype != NULL) {
203                         if (FSINFO(impl_share, fstype)->active &&
204                             FSINFO(impl_share, fstype)->shareopts != NULL) {
205                                 resource = FSINFO(impl_share, fstype)->resource;
206
207                                 if (resource == NULL)
208                                         resource = "-";
209
210                                 fprintf(temp_fp, "%s\t%s\t%s\t%s\n",
211                                     impl_share->sharepath, resource,
212                                     fstype->name,
213                                     FSINFO(impl_share, fstype)->shareopts);
214                         }
215
216                         fstype = fstype->next;
217                 }
218
219                 impl_share = impl_share->next;
220         }
221
222         fflush(temp_fp);
223         fsync(temp_fd);
224         fclose(temp_fp);
225
226         rename(tempfile, "/etc/dfs/sharetab");
227 }
228
229 typedef struct update_cookie_s {
230         sa_handle_impl_t handle;
231         const char *proto;
232 } update_cookie_t;
233
234 static int
235 update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie)
236 {
237         update_cookie_t *udata = (update_cookie_t *)pcookie;
238         char mountpoint[ZFS_MAXPROPLEN];
239         char shareopts[ZFS_MAXPROPLEN];
240         char *dataset;
241         zfs_type_t type = zfs_get_type(zhp);
242
243         if (type == ZFS_TYPE_FILESYSTEM &&
244             zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) {
245                 zfs_close(zhp);
246                 return 1;
247         }
248
249         if (type != ZFS_TYPE_FILESYSTEM) {
250                 zfs_close(zhp);
251                 return 0;
252         }
253
254         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
255             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
256                 zfs_close(zhp);
257                 return 0;
258         }
259
260         dataset = (char *)zfs_get_name(zhp);
261
262         if (dataset == NULL) {
263                 zfs_close(zhp);
264                 return 0;
265         }
266
267         if (!zfs_is_mounted(zhp, NULL)) {
268                 zfs_close(zhp);
269                 return 0;
270         }
271
272         if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) &&
273             zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
274             sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
275             strcmp(shareopts, "off") != 0) {
276                 (void) process_share(udata->handle, NULL, mountpoint, NULL,
277                     "nfs", shareopts, NULL, dataset, B_FALSE);
278         }
279
280         if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) &&
281             zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts,
282             sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
283             strcmp(shareopts, "off") != 0) {
284                 (void) process_share(udata->handle, NULL, mountpoint, NULL,
285                     "smb", shareopts, NULL, dataset, B_FALSE);
286         }
287
288         zfs_close(zhp);
289
290         return 0;
291 }
292
293 static int
294 update_zfs_share(sa_share_impl_t impl_share, const char *proto)
295 {
296         sa_handle_impl_t impl_handle = impl_share->handle;
297         zfs_handle_t *zhp;
298         update_cookie_t udata;
299
300         if (impl_handle->zfs_libhandle == NULL)
301                         return SA_SYSTEM_ERR;
302
303         assert(impl_share->dataset != NULL);
304
305         zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset,
306             ZFS_TYPE_FILESYSTEM);
307
308         if (zhp == NULL)
309                 return SA_SYSTEM_ERR;
310
311         udata.handle = impl_handle;
312         udata.proto = proto;
313         (void) update_zfs_shares_cb(zhp, &udata);
314
315         return SA_OK;
316 }
317
318 static int
319 update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto)
320 {
321         update_cookie_t udata;
322
323         if (impl_handle->zfs_libhandle == NULL)
324                 return SA_SYSTEM_ERR;
325
326         udata.handle = impl_handle;
327         udata.proto = proto;
328         (void) zfs_iter_root(impl_handle->zfs_libhandle, update_zfs_shares_cb,
329             &udata);
330
331         return SA_OK;
332 }
333
334 static int
335 process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share,
336     char *pathname, char *resource, char *proto,
337     char *options, char *description, char *dataset,
338     boolean_t from_sharetab)
339 {
340         struct stat statbuf;
341         int rc;
342         char *resource_dup = NULL, *dataset_dup = NULL;
343         boolean_t new_share;
344         sa_fstype_t *fstype;
345
346         new_share = B_FALSE;
347
348         if (impl_share == NULL)
349                 impl_share = find_share(impl_handle, pathname);
350
351         if (impl_share == NULL) {
352                 if (lstat(pathname, &statbuf) != 0 ||
353                     !S_ISDIR(statbuf.st_mode))
354                         return SA_BAD_PATH;
355
356                 impl_share = alloc_share(pathname);
357
358                 if (impl_share == NULL) {
359                         rc = SA_NO_MEMORY;
360                         goto err;
361                 }
362
363                 new_share = B_TRUE;
364         }
365
366         if (dataset != NULL) {
367                 dataset_dup = strdup(dataset);
368
369                 if (dataset_dup == NULL) {
370                         rc = SA_NO_MEMORY;
371                         goto err;
372                 }
373         }
374
375         free(impl_share->dataset);
376         impl_share->dataset = dataset_dup;
377
378         rc = SA_INVALID_PROTOCOL;
379
380         fstype = fstypes;
381         while (fstype != NULL) {
382                 if (strcmp(fstype->name, proto) == 0) {
383                         if (resource != NULL) {
384                                 resource_dup = strdup(resource);
385
386                                 if (resource_dup == NULL) {
387                                         rc = SA_NO_MEMORY;
388                                         goto err;
389                                 }
390                         }
391
392                         free(FSINFO(impl_share, fstype)->resource);
393                         FSINFO(impl_share, fstype)->resource = resource_dup;
394
395                         rc = fstype->ops->update_shareopts(impl_share,
396                             resource, options);
397
398                         if (rc == SA_OK && from_sharetab)
399                                 FSINFO(impl_share, fstype)->active = B_TRUE;
400
401                         break;
402                 }
403
404                 fstype = fstype->next;
405         }
406
407         if (rc != SA_OK)
408                 goto err;
409
410         if (new_share) {
411                 impl_share->handle = impl_handle;
412
413                 impl_share->next = impl_handle->shares;
414                 impl_handle->shares = impl_share;
415
416         }
417
418 err:
419         if (rc != SA_OK) {
420                 if (new_share)
421                         free_share(impl_share);
422         }
423
424         return rc;
425 }
426
427 void
428 sa_fini(sa_handle_t handle)
429 {
430         sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
431         sa_share_impl_t impl_share, next;
432         sa_share_impl_t *pcurr;
433
434         if (impl_handle == NULL)
435                 return;
436
437         /*
438          * clean up shares which don't have a non-NULL dataset property,
439          * which means they're in sharetab but we couldn't find their
440          * ZFS dataset.
441          */
442         pcurr = &(impl_handle->shares);
443         impl_share = *pcurr;
444         while (impl_share != NULL) {
445                 next = impl_share->next;
446
447                 if (impl_share->dataset == NULL) {
448                         /* remove item from the linked list */
449                         *pcurr = next;
450
451                         sa_disable_share(impl_share, NULL);
452
453                         free_share(impl_share);
454                 } else {
455                         pcurr = &(impl_share->next);
456                 }
457
458                 impl_share = next;
459         }
460
461         update_sharetab(impl_handle);
462
463         if (impl_handle->zfs_libhandle != NULL)
464                 libzfs_fini(impl_handle->zfs_libhandle);
465
466         impl_share = impl_handle->shares;
467         while (impl_share != NULL) {
468                 next = impl_share->next;
469                 free_share(impl_share);
470                 impl_share = next;
471         }
472
473         free(impl_handle);
474 }
475
476 static sa_share_impl_t
477 find_share(sa_handle_impl_t impl_handle, const char *sharepath)
478 {
479         sa_share_impl_t impl_share;
480
481         impl_share = impl_handle->shares;
482         while (impl_share != NULL) {
483                 if (strcmp(impl_share->sharepath, sharepath) == 0) {
484                         break;
485                 }
486
487                 impl_share = impl_share->next;
488         }
489
490         return impl_share;
491 }
492
493 sa_share_t
494 sa_find_share(sa_handle_t handle, char *sharepath)
495 {
496         return (sa_share_t)find_share((sa_handle_impl_t)handle, sharepath);
497 }
498
499 int
500 sa_enable_share(sa_share_t share, char *protocol)
501 {
502         sa_share_impl_t impl_share = (sa_share_impl_t)share;
503         int rc, ret;
504         boolean_t found_protocol;
505         sa_fstype_t *fstype;
506
507 #ifdef DEBUG
508         fprintf(stderr, "sa_enable_share: share->sharepath=%s, protocol=%s\n",
509                 impl_share->sharepath, protocol);
510 #endif
511
512         assert(impl_share->handle != NULL);
513
514         ret = SA_OK;
515         found_protocol = B_FALSE;
516
517         fstype = fstypes;
518         while (fstype != NULL) {
519                 if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
520                         update_zfs_share(impl_share, fstype->name);
521
522                         rc = fstype->ops->enable_share(impl_share);
523
524                         if (rc != SA_OK)
525                                 ret = rc;
526                         else
527                                 FSINFO(impl_share, fstype)->active = B_TRUE;
528
529                         found_protocol = B_TRUE;
530                 }
531
532                 fstype = fstype->next;
533         }
534
535         update_sharetab(impl_share->handle);
536
537         return (found_protocol ? ret : SA_INVALID_PROTOCOL);
538 }
539
540 int
541 sa_disable_share(sa_share_t share, char *protocol)
542 {
543         sa_share_impl_t impl_share = (sa_share_impl_t)share;
544         int rc, ret;
545         boolean_t found_protocol;
546         sa_fstype_t *fstype;
547
548 #ifdef DEBUG
549         fprintf(stderr, "sa_disable_share: share->sharepath=%s, protocol=%s\n",
550                 impl_share->sharepath, protocol);
551 #endif
552
553         ret = SA_OK;
554         found_protocol = B_FALSE;
555
556         fstype = fstypes;
557         while (fstype != NULL) {
558                 if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
559                         rc = fstype->ops->disable_share(impl_share);
560
561                         if (rc == SA_OK) {
562                                 fstype->ops->clear_shareopts(impl_share);
563
564                                 FSINFO(impl_share, fstype)->active = B_FALSE;
565                         } else
566                                 ret = rc;
567
568                         found_protocol = B_TRUE;
569                 }
570
571                 fstype = fstype->next;
572         }
573
574         update_sharetab(impl_share->handle);
575
576         return (found_protocol ? ret : SA_INVALID_PROTOCOL);
577 }
578
579 /*
580  * sa_errorstr(err)
581  *
582  * convert an error value to an error string
583  */
584 char *
585 sa_errorstr(int err)
586 {
587         static char errstr[32];
588         char *ret = NULL;
589
590         switch (err) {
591         case SA_OK:
592                 ret = dgettext(TEXT_DOMAIN, "ok");
593                 break;
594         case SA_NO_SUCH_PATH:
595                 ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
596                 break;
597         case SA_NO_MEMORY:
598                 ret = dgettext(TEXT_DOMAIN, "no memory");
599                 break;
600         case SA_DUPLICATE_NAME:
601                 ret = dgettext(TEXT_DOMAIN, "name in use");
602                 break;
603         case SA_BAD_PATH:
604                 ret = dgettext(TEXT_DOMAIN, "bad path");
605                 break;
606         case SA_NO_SUCH_GROUP:
607                 ret = dgettext(TEXT_DOMAIN, "no such group");
608                 break;
609         case SA_CONFIG_ERR:
610                 ret = dgettext(TEXT_DOMAIN, "configuration error");
611                 break;
612         case SA_SYSTEM_ERR:
613                 ret = dgettext(TEXT_DOMAIN, "system error");
614                 break;
615         case SA_SYNTAX_ERR:
616                 ret = dgettext(TEXT_DOMAIN, "syntax error");
617                 break;
618         case SA_NO_PERMISSION:
619                 ret = dgettext(TEXT_DOMAIN, "no permission");
620                 break;
621         case SA_BUSY:
622                 ret = dgettext(TEXT_DOMAIN, "busy");
623                 break;
624         case SA_NO_SUCH_PROP:
625                 ret = dgettext(TEXT_DOMAIN, "no such property");
626                 break;
627         case SA_INVALID_NAME:
628                 ret = dgettext(TEXT_DOMAIN, "invalid name");
629                 break;
630         case SA_INVALID_PROTOCOL:
631                 ret = dgettext(TEXT_DOMAIN, "invalid protocol");
632                 break;
633         case SA_NOT_ALLOWED:
634                 ret = dgettext(TEXT_DOMAIN, "operation not allowed");
635                 break;
636         case SA_BAD_VALUE:
637                 ret = dgettext(TEXT_DOMAIN, "bad property value");
638                 break;
639         case SA_INVALID_SECURITY:
640                 ret = dgettext(TEXT_DOMAIN, "invalid security type");
641                 break;
642         case SA_NO_SUCH_SECURITY:
643                 ret = dgettext(TEXT_DOMAIN, "security type not found");
644                 break;
645         case SA_VALUE_CONFLICT:
646                 ret = dgettext(TEXT_DOMAIN, "property value conflict");
647                 break;
648         case SA_NOT_IMPLEMENTED:
649                 ret = dgettext(TEXT_DOMAIN, "not implemented");
650                 break;
651         case SA_INVALID_PATH:
652                 ret = dgettext(TEXT_DOMAIN, "invalid path");
653                 break;
654         case SA_NOT_SUPPORTED:
655                 ret = dgettext(TEXT_DOMAIN, "operation not supported");
656                 break;
657         case SA_PROP_SHARE_ONLY:
658                 ret = dgettext(TEXT_DOMAIN, "property not valid for group");
659                 break;
660         case SA_NOT_SHARED:
661                 ret = dgettext(TEXT_DOMAIN, "not shared");
662                 break;
663         case SA_NO_SUCH_RESOURCE:
664                 ret = dgettext(TEXT_DOMAIN, "no such resource");
665                 break;
666         case SA_RESOURCE_REQUIRED:
667                 ret = dgettext(TEXT_DOMAIN, "resource name required");
668                 break;
669         case SA_MULTIPLE_ERROR:
670                 ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
671                 break;
672         case SA_PATH_IS_SUBDIR:
673                 ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
674                 break;
675         case SA_PATH_IS_PARENTDIR:
676                 ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
677                 break;
678         case SA_NO_SECTION:
679                 ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
680                 break;
681         case SA_NO_PROPERTIES:
682                 ret = dgettext(TEXT_DOMAIN, "properties not found");
683                 break;
684         case SA_NO_SUCH_SECTION:
685                 ret = dgettext(TEXT_DOMAIN, "section not found");
686                 break;
687         case SA_PASSWORD_ENC:
688                 ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
689                 break;
690         case SA_SHARE_EXISTS:
691                 ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
692                 break;
693         default:
694                 (void) snprintf(errstr, sizeof (errstr),
695                     dgettext(TEXT_DOMAIN, "unknown %d"), err);
696                 ret = errstr;
697         }
698         return (ret);
699 }
700
701 int
702 sa_parse_legacy_options(sa_group_t group, char *options, char *proto)
703 {
704         sa_fstype_t *fstype;
705
706 #ifdef DEBUG
707         fprintf(stderr, "sa_parse_legacy_options: options=%s, proto=%s\n",
708                 options, proto);
709 #endif
710
711         fstype = fstypes;
712         while (fstype != NULL) {
713                 if (strcmp(fstype->name, proto) != 0) {
714                         fstype = fstype->next;
715                         continue;
716                 }
717
718                 return fstype->ops->validate_shareopts(options);
719         }
720
721         return SA_INVALID_PROTOCOL;
722 }
723
724 boolean_t
725 sa_needs_refresh(sa_handle_t handle)
726 {
727         return B_TRUE;
728 }
729
730 libzfs_handle_t *
731 sa_get_zfs_handle(sa_handle_t handle)
732 {
733         sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
734
735         if (impl_handle == NULL)
736                 return NULL;
737
738         return impl_handle->zfs_libhandle;
739 }
740
741 static sa_share_impl_t
742 alloc_share(const char *sharepath)
743 {
744         sa_share_impl_t impl_share;
745
746         impl_share = calloc(sizeof (struct sa_share_impl), 1);
747
748         if (impl_share == NULL)
749                 return NULL;
750
751         impl_share->sharepath = strdup(sharepath);
752
753         if (impl_share->sharepath == NULL) {
754                 free(impl_share);
755                 return NULL;
756         }
757
758         impl_share->fsinfo = calloc(sizeof (sa_share_fsinfo_t), fstypes_count);
759
760         if (impl_share->fsinfo == NULL) {
761                 free(impl_share->sharepath);
762                 free(impl_share);
763                 return NULL;
764         }
765
766         return impl_share;
767 }
768
769 static void
770 free_share(sa_share_impl_t impl_share) {
771         sa_fstype_t *fstype;
772
773         fstype = fstypes;
774         while (fstype != NULL) {
775                 fstype->ops->clear_shareopts(impl_share);
776
777                 free(FSINFO(impl_share, fstype)->resource);
778
779                 fstype = fstype->next;
780         }
781
782         free(impl_share->sharepath);
783         free(impl_share->dataset);
784         free(impl_share->fsinfo);
785         free(impl_share);
786 }
787
788 int
789 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
790     char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
791     char *sourcestr, char *dataset)
792 {
793         sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
794         sa_share_impl_t impl_share = (sa_share_impl_t)share;
795
796 #ifdef DEBUG
797         fprintf(stderr, "sa_zfs_process_share: mountpoint=%s, proto=%s, "
798             "shareopts=%s, sourcestr=%s, dataset=%s\n", mountpoint, proto,
799             shareopts, sourcestr, dataset);
800 #endif
801
802         return process_share(impl_handle, impl_share, mountpoint, NULL,
803             proto, shareopts, NULL, dataset, B_FALSE);
804 }
805
806 void
807 sa_update_sharetab_ts(sa_handle_t handle)
808 {
809         sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
810
811         update_sharetab(impl_handle);
812 }