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