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 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 */
28
29 #include <stdio.h>
30 #include <libzfs.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <errno.h>
34 #include <libshare.h>
35 #include "libshare_impl.h"
36 #include <libintl.h>
37 #include <sys/mnttab.h>
38 #include <sys/mntent.h>
39
40 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
41 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
42 extern char *sa_fstype(char *);
43 extern void set_node_attr(void *, char *, char *);
44 extern int sa_is_share(void *);
45 extern void sa_update_sharetab_ts(sa_handle_t);
46
47 /*
48 * File system specific code for ZFS. The original code was stolen
49 * from the "zfs" command and modified to better suit this library's
50 * usage.
51 */
52
53 typedef struct get_all_cbdata {
54 zfs_handle_t **cb_handles;
55 size_t cb_alloc;
56 size_t cb_used;
57 uint_t cb_types;
58 } get_all_cbdata_t;
59
60 /*
61 * sa_zfs_init(impl_handle)
62 *
63 * Initialize an access handle into libzfs. The handle needs to stay
64 * around until sa_zfs_fini() in order to maintain the cache of
65 * mounts.
66 */
67
68 int
69 sa_zfs_init(sa_handle_impl_t impl_handle)
70 {
71 impl_handle->zfs_libhandle = libzfs_init();
72 if (impl_handle->zfs_libhandle != NULL) {
73 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
74 return (B_TRUE);
75 }
76 return (B_FALSE);
77 }
78
79 /*
80 * sa_zfs_fini(impl_handle)
81 *
82 * cleanup data structures and the libzfs handle used for accessing
83 * zfs file share info.
84 */
85
86 void
87 sa_zfs_fini(sa_handle_impl_t impl_handle)
88 {
89 if (impl_handle->zfs_libhandle != NULL) {
90 if (impl_handle->zfs_list != NULL) {
91 zfs_handle_t **zhp = impl_handle->zfs_list;
92 size_t i;
93
94 /*
95 * Contents of zfs_list need to be freed so we
96 * don't lose ZFS handles.
97 */
98 for (i = 0; i < impl_handle->zfs_list_count; i++) {
99 zfs_close(zhp[i]);
100 }
101 free(impl_handle->zfs_list);
102 impl_handle->zfs_list = NULL;
103 impl_handle->zfs_list_count = 0;
104 }
105
106 libzfs_fini(impl_handle->zfs_libhandle);
107 impl_handle->zfs_libhandle = NULL;
108 }
109 }
110
111 /*
112 * get_one_filesystem(zfs_handle_t, data)
113 *
114 * an iterator function called while iterating through the ZFS
115 * root. It accumulates into an array of file system handles that can
116 * be used to derive info about those file systems.
117 *
118 * Note that as this function is called, we close all zhp handles that
119 * are not going to be places into the cp_handles list. We don't want
120 * to close the ones we are keeping, but all others would be leaked if
121 * not closed here.
122 */
123
124 static int
125 get_one_filesystem(zfs_handle_t *zhp, void *data)
126 {
127 get_all_cbdata_t *cbp = data;
166 }
167
168 cbp->cb_handles = handles;
169 }
170
171 cbp->cb_handles[cbp->cb_used++] = zhp;
172
173 return (0);
174 }
175
176 /*
177 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
178 *
179 * iterate through all ZFS file systems starting at the root. Returns
180 * a count and an array of handle pointers. Allocating is only done
181 * once. The caller does not need to free since it will be done at
182 * sa_zfs_fini() time.
183 */
184
185 static void
186 get_all_filesystems(sa_handle_impl_t impl_handle,
187 zfs_handle_t ***fslist, size_t *count)
188 {
189 get_all_cbdata_t cb = { 0 };
190 cb.cb_types = ZFS_TYPE_FILESYSTEM;
191
192 if (impl_handle->zfs_list != NULL) {
193 *fslist = impl_handle->zfs_list;
194 *count = impl_handle->zfs_list_count;
195 return;
196 }
197
198 (void) zfs_iter_root(impl_handle->zfs_libhandle,
199 get_one_filesystem, &cb);
200
201 impl_handle->zfs_list = *fslist = cb.cb_handles;
202 impl_handle->zfs_list_count = *count = cb.cb_used;
203 }
204
205 /*
206 * mountpoint_compare(a, b)
207 *
208 * compares the mountpoint on two zfs file systems handles.
209 * returns values following strcmp() model.
210 */
211
212 static int
213 mountpoint_compare(const void *a, const void *b)
214 {
215 zfs_handle_t **za = (zfs_handle_t **)a;
216 zfs_handle_t **zb = (zfs_handle_t **)b;
217 char mounta[MAXPATHLEN];
218 char mountb[MAXPATHLEN];
219
220 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
221 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
222 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
244
245 if (entry.mnt_fstype == NULL ||
246 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
247 continue;
248
249 if (strcmp(entry.mnt_mountp, path) == 0) {
250 if (mlen > 0)
251 (void) strlcpy(mountpoint, entry.mnt_mountp,
252 mlen);
253 if (dlen > 0)
254 (void) strlcpy(dataset, entry.mnt_special,
255 dlen);
256 break;
257 }
258 }
259 (void) fclose(fp);
260 return (1);
261 }
262
263 /*
264 * get_zfs_dataset(impl_handle, path)
265 *
266 * get the name of the ZFS dataset the path is equivalent to. The
267 * dataset name is used for get/set of ZFS properties since libzfs
268 * requires a dataset to do a zfs_open().
269 */
270
271 static char *
272 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path,
273 boolean_t search_mnttab)
274 {
275 size_t i, count = 0;
276 char *dataset = NULL;
277 zfs_handle_t **zlist;
278 char mountpoint[ZFS_MAXPROPLEN];
279 char canmount[ZFS_MAXPROPLEN];
280
281 get_all_filesystems(impl_handle, &zlist, &count);
282 qsort(zlist, count, sizeof (void *), mountpoint_compare);
283 for (i = 0; i < count; i++) {
284 /* must have a mountpoint */
285 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint,
286 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
287 /* no mountpoint */
288 continue;
289 }
290
291 /* mountpoint must be a path */
292 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
293 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
294 /*
295 * Search mmttab for mountpoint and get dataset.
296 */
297
298 if (search_mnttab == B_TRUE &&
299 get_legacy_mountpoint(path, mountpoint,
300 sizeof (mountpoint), NULL, 0) == 0) {
301 dataset = mountpoint;
318 if (strcmp(mountpoint, path) == 0) {
319 dataset = (char *)zfs_get_name(zlist[i]);
320 break;
321 }
322
323 }
324
325 if (dataset != NULL)
326 dataset = strdup(dataset);
327
328 return (dataset);
329 }
330
331 /*
332 * get_zfs_property(dataset, property)
333 *
334 * Get the file system property specified from the ZFS dataset.
335 */
336
337 static char *
338 get_zfs_property(char *dataset, zfs_prop_t property)
339 {
340 zfs_handle_t *handle = NULL;
341 char shareopts[ZFS_MAXPROPLEN];
342 libzfs_handle_t *libhandle;
343
344 libhandle = libzfs_init();
345 if (libhandle != NULL) {
346 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM);
347 if (handle != NULL) {
348 if (zfs_prop_get(handle, property, shareopts,
349 sizeof (shareopts), NULL, NULL, 0,
350 B_FALSE) == 0) {
351 zfs_close(handle);
352 libzfs_fini(libhandle);
353 return (strdup(shareopts));
354 }
355 zfs_close(handle);
356 }
357 libzfs_fini(libhandle);
358 }
359 return (NULL);
360 }
361
362 /*
363 * sa_zfs_is_shared(handle, path)
364 *
365 * Check to see if the ZFS path provided has the sharenfs option set
366 * or not.
367 */
368
369 int
370 sa_zfs_is_shared(sa_handle_t sahandle, char *path)
371 {
372 int ret = 0;
373 char *dataset;
374 zfs_handle_t *handle = NULL;
375 char shareopts[ZFS_MAXPROPLEN];
376 libzfs_handle_t *libhandle;
377
378 dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE);
379 if (dataset != NULL) {
380 libhandle = libzfs_init();
381 if (libhandle != NULL) {
382 handle = zfs_open(libhandle, dataset,
383 ZFS_TYPE_FILESYSTEM);
384 if (handle != NULL) {
385 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS,
386 shareopts, sizeof (shareopts), NULL, NULL,
387 0, B_FALSE) == 0 &&
388 strcmp(shareopts, "off") != 0) {
389 ret = 1; /* it is shared */
390 }
391 zfs_close(handle);
392 }
393 libzfs_fini(libhandle);
394 }
395 free(dataset);
396 }
397 return (ret);
398 }
399
400 /*
401 * find_or_create_group(handle, groupname, proto, *err)
402 *
403 * While walking the ZFS tree, we need to add shares to a defined
404 * group. If the group doesn't exist, create it first, making sure it
405 * is marked as a ZFS group.
406 *
407 * Note that all ZFS shares are in a subgroup of the top level group
408 * called "zfs".
409 */
410
411 static sa_group_t
412 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
413 {
746 sa_group_t zfsgroup;
747 boolean_t nfs;
748 boolean_t nfs_inherited;
749 boolean_t smb;
750 boolean_t smb_inherited;
751 zfs_handle_t **zlist;
752 char nfsshareopts[ZFS_MAXPROPLEN];
753 char smbshareopts[ZFS_MAXPROPLEN];
754 sa_share_t share;
755 zprop_source_t source;
756 char nfssourcestr[ZFS_MAXPROPLEN];
757 char smbsourcestr[ZFS_MAXPROPLEN];
758 char mountpoint[ZFS_MAXPROPLEN];
759 size_t count = 0, i;
760 libzfs_handle_t *zfs_libhandle;
761 int err = SA_OK;
762
763 /*
764 * If we can't access libzfs, don't bother doing anything.
765 */
766 zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
767 if (zfs_libhandle == NULL)
768 return (SA_SYSTEM_ERR);
769
770 zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
771 /* Not an error, this could be a legacy condition */
772 if (zfsgroup == NULL)
773 return (SA_OK);
774
775 /*
776 * need to walk the mounted ZFS pools and datasets to
777 * find shares that are possible.
778 */
779 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
780 qsort(zlist, count, sizeof (void *), mountpoint_compare);
781
782 for (i = 0; i < count; i++) {
783 char *dataset;
784
785 source = ZPROP_SRC_ALL;
786 /* If no mountpoint, skip. */
787 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT,
788 mountpoint, sizeof (mountpoint), NULL, NULL, 0,
789 B_FALSE) != 0)
790 continue;
791
792 /*
793 * zfs_get_name value must not be freed. It is just a
794 * pointer to a value in the handle.
795 */
796 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL)
797 continue;
798
799 /*
915
916 /*
917 * sa_zfs_set_sharenfs(group, path, on)
918 *
919 * Update the "sharenfs" property on the path. If on is true, then set
920 * to the properties on the group or "on" if no properties are
921 * defined. Set to "off" if on is false.
922 */
923
924 int
925 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
926 {
927 int ret = SA_NOT_IMPLEMENTED;
928 char *command;
929
930 command = malloc(ZFS_MAXPROPLEN * 2);
931 if (command != NULL) {
932 char *opts = NULL;
933 char *dataset = NULL;
934 FILE *pfile;
935 sa_handle_impl_t impl_handle;
936 /* for now, NFS is always available for "zfs" */
937 if (on) {
938 opts = sa_proto_legacy_format("nfs", group, 1);
939 if (opts != NULL && strlen(opts) == 0) {
940 free(opts);
941 opts = strdup("on");
942 }
943 }
944
945 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
946 assert(impl_handle != NULL);
947 if (impl_handle != NULL)
948 dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
949 else
950 ret = SA_SYSTEM_ERR;
951
952 if (dataset != NULL) {
953 (void) snprintf(command, ZFS_MAXPROPLEN * 2,
954 "%s set sharenfs=\"%s\" %s", COMMAND,
955 opts != NULL ? opts : "off", dataset);
956 pfile = popen(command, "r");
957 if (pfile != NULL) {
958 ret = pclose(pfile);
959 if (ret != 0)
960 ret = SA_SYSTEM_ERR;
961 }
962 }
963 if (opts != NULL)
964 free(opts);
965 if (dataset != NULL)
966 free(dataset);
967 free(command);
968 }
1026 * to the properties on the group or "on" if no properties are
1027 * defined. Set to "off" if on is false.
1028 */
1029
1030 int
1031 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
1032 {
1033 int ret = SA_NOT_IMPLEMENTED;
1034 char *command;
1035 sa_share_t share;
1036
1037 /* In case SMB not enabled */
1038 if (sa_get_optionset(group, "smb") == NULL)
1039 return (SA_NOT_SUPPORTED);
1040
1041 command = malloc(ZFS_MAXPROPLEN * 2);
1042 if (command != NULL) {
1043 char *opts = NULL;
1044 char *dataset = NULL;
1045 FILE *pfile;
1046 sa_handle_impl_t impl_handle;
1047
1048 if (on) {
1049 char *newopt;
1050
1051 share = sa_get_share(group, NULL);
1052 opts = sa_proto_legacy_format("smb", share, 1);
1053 if (opts != NULL && strlen(opts) == 0) {
1054 free(opts);
1055 opts = strdup("on");
1056 }
1057 newopt = add_resources(opts, share);
1058 free(opts);
1059 opts = newopt;
1060 }
1061
1062 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1063 assert(impl_handle != NULL);
1064 if (impl_handle != NULL)
1065 dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
1066 else
1067 ret = SA_SYSTEM_ERR;
1068
1069 if (dataset != NULL) {
1070 (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1071 "echo %s set sharesmb=\"%s\" %s", COMMAND,
1072 opts != NULL ? opts : "off", dataset);
1073 pfile = popen(command, "r");
1074 if (pfile != NULL) {
1075 ret = pclose(pfile);
1076 if (ret != 0)
1077 ret = SA_SYSTEM_ERR;
1078 }
1079 }
1080 if (opts != NULL)
1081 free(opts);
1082 if (dataset != NULL)
1083 free(dataset);
1084 free(command);
1085 }
1109 parent = group;
1110
1111 if (parent != NULL) {
1112 command = malloc(ZFS_MAXPROPLEN * 2);
1113 if (command == NULL)
1114 return (SA_NO_MEMORY);
1115
1116 *command = '\0';
1117 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL;
1118 protopt = sa_get_next_optionset(protopt)) {
1119
1120 char *proto = sa_get_optionset_attr(protopt, "type");
1121 char *path;
1122 char *dataset = NULL;
1123 char *zfsopts = NULL;
1124
1125 if (sa_is_share(group)) {
1126 path = sa_get_share_attr((sa_share_t)group,
1127 "path");
1128 if (path != NULL) {
1129 sa_handle_impl_t impl_handle;
1130
1131 impl_handle = sa_find_group_handle(
1132 group);
1133 if (impl_handle != NULL)
1134 dataset = get_zfs_dataset(
1135 impl_handle, path, B_FALSE);
1136 else
1137 ret = SA_SYSTEM_ERR;
1138
1139 sa_free_attr_string(path);
1140 }
1141 } else {
1142 dataset = sa_get_group_attr(group, "name");
1143 }
1144 /* update only when there is an optstring found */
1145 doupdate = 0;
1146 if (proto != NULL && dataset != NULL) {
1147 optstring = sa_proto_legacy_format(proto,
1148 group, 1);
1149 zfsopts = get_zfs_property(dataset,
1150 ZFS_PROP_SHARENFS);
1151
1152 if (optstring != NULL && zfsopts != NULL) {
1153 if (strcmp(optstring, zfsopts) != 0)
1154 doupdate++;
1155 }
1156 if (doupdate) {
1157 if (optstring != NULL &&
1158 strlen(optstring) > 0) {
1159 (void) snprintf(command,
1160 ZFS_MAXPROPLEN * 2,
1161 "%s set share%s=%s %s",
1162 COMMAND, proto,
1163 optstring, dataset);
1164 } else {
1165 (void) snprintf(command,
1166 ZFS_MAXPROPLEN * 2,
1167 "%s set share%s=on %s",
1168 COMMAND, proto,
1169 dataset);
1187 free(optstring);
1188 if (zfsopts != NULL)
1189 free(zfsopts);
1190 }
1191 if (proto != NULL)
1192 sa_free_attr_string(proto);
1193 if (dataset != NULL)
1194 free(dataset);
1195 }
1196 free(command);
1197 }
1198 return (ret);
1199 }
1200
1201 /*
1202 * sa_group_is_zfs(group)
1203 *
1204 * Given the group, determine if the zfs attribute is set.
1205 */
1206
1207 int
1208 sa_group_is_zfs(sa_group_t group)
1209 {
1210 char *zfs;
1211 int ret = 0;
1212
1213 zfs = sa_get_group_attr(group, "zfs");
1214 if (zfs != NULL) {
1215 ret = 1;
1216 sa_free_attr_string(zfs);
1217 }
1218 return (ret);
1219 }
1220
1221 /*
1222 * sa_path_is_zfs(path)
1223 *
1224 * Check to see if the file system path represents is of type "zfs".
1225 */
1226
1227 int
1228 sa_path_is_zfs(char *path)
1229 {
1230 char *fstype;
1231 int ret = 0;
1232
1233 fstype = sa_fstype(path);
1234 if (fstype != NULL && strcmp(fstype, "zfs") == 0)
1235 ret = 1;
1236 if (fstype != NULL)
1237 sa_free_fstype(fstype);
1238 return (ret);
1239 }
1240
1241 int
1242 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
1243 {
1244 char *path;
1245
1246 /* Make sure path is valid */
1247
1248 path = sa_get_share_attr(share, "path");
1249 if (path != NULL) {
1250 (void) memset(sh, 0, sizeof (sh));
1251 (void) sa_fillshare(share, proto, sh);
1252 sa_free_attr_string(path);
1253 return (0);
1254 } else
1255 return (1);
1256 }
1257
1258 #define SMAX(i, j) \
1259 if ((j) > (i)) { \
1260 (i) = (j); \
1261 }
1262
1263 int
1264 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh,
1265 void *exportdata, zfs_share_op_t operation)
1266 {
1267 libzfs_handle_t *libhandle;
1268 sa_group_t group;
1269 sa_handle_t sahandle;
1270 char *dataset;
1271 int err = EINVAL;
1272 int i, j;
1273 char newpath[MAXPATHLEN];
1274 char *pathp;
1275
1276 /*
1277 * First find the dataset name
1278 */
1279 if ((group = sa_get_parent_group(share)) == NULL) {
1280 return (EINVAL);
1281 }
1282 if ((sahandle = sa_find_group_handle(group)) == NULL) {
1283 return (EINVAL);
1284 }
1285
1286 /*
1287 * If get_zfs_dataset fails, see if it is a subdirectory
1288 */
1289
1290 pathp = path;
1291 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) {
1292 char *p;
1293
1294 if (pathp == path) {
1295 (void) strlcpy(newpath, path, sizeof (newpath));
1296 pathp = newpath;
1297 }
1298
1299 /*
1300 * Make sure only one leading '/' This condition came
1301 * about when using HAStoragePlus which insisted on
1302 * putting an extra leading '/' in the ZFS path
1303 * name. The problem is fixed in other areas, but this
1304 * will catch any other ways that a double slash might
1305 * get introduced.
1306 */
1307 while (*pathp == '/' && *(pathp + 1) == '/')
1308 pathp++;
1309
1310 /*
1311 * chop off part of path, but if we are at root then
1312 * make sure path is a /
1313 */
1314 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) {
1315 if (pathp == p) {
1316 *(p + 1) = '\0'; /* skip over /, root case */
1317 } else {
1318 *p = '\0';
1319 }
1320 } else {
1321 return (EINVAL);
1322 }
1323 }
1324
1325 libhandle = libzfs_init();
1326 if (libhandle != NULL) {
1327 char *resource_name;
1328
1329 i = (sh->sh_path ? strlen(sh->sh_path) : 0);
1330 sh->sh_size = i;
1331
1332 j = (sh->sh_res ? strlen(sh->sh_res) : 0);
1333 sh->sh_size += j;
1334 SMAX(i, j);
1335
1336 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
1337 sh->sh_size += j;
1338 SMAX(i, j);
1339
1340 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
1341 sh->sh_size += j;
1342 SMAX(i, j);
1343
1344 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
1345 sh->sh_size += j;
1346 SMAX(i, j);
1347
1348 resource_name = sa_get_resource_attr(resource, "name");
1349
1350 err = zfs_deleg_share_nfs(libhandle, dataset, path,
1351 resource_name, exportdata, sh, i, operation);
1352 if (err == SA_OK)
1353 sa_update_sharetab_ts(sahandle);
1354 else
1355 err = errno;
1356 if (resource_name)
1357 sa_free_attr_string(resource_name);
1358
1359 libzfs_fini(libhandle);
1360 }
1361 free(dataset);
1362 return (err);
1363 }
1364
1365 /*
1366 * sa_get_zfs_handle(handle)
1367 *
1368 * Given an sa_handle_t, return the libzfs_handle_t *. This is only
1369 * used internally by libzfs. Needed in order to avoid including
1370 * libshare_impl.h in libzfs.
1371 */
1372
1373 libzfs_handle_t *
1374 sa_get_zfs_handle(sa_handle_t handle)
1375 {
1376 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
1377
1378 return (implhandle->zfs_libhandle);
1379 }
1380
1381 /*
1382 * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
1383 *
1384 * Find the ZFS dataset and mountpoint for a given path
1385 */
1386 int
1387 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp,
1388 char *datasetp)
1389 {
1390 get_all_cbdata_t cb = { 0 };
1391 int i;
1392 char mountpoint[ZFS_MAXPROPLEN];
1393 char dataset[ZFS_MAXPROPLEN];
1394 char canmount[ZFS_MAXPROPLEN];
1395 char *dp;
1396 int count;
1397 int ret = 0;
1398
1399 cb.cb_types = ZFS_TYPE_FILESYSTEM;
1400
1401 if (libzfs == NULL)
1402 return (0);
1403
1404 (void) zfs_iter_root(libzfs, get_one_filesystem, &cb);
1405 count = cb.cb_used;
1406
1407 qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare);
1408 for (i = 0; i < count; i++) {
1409 /* must have a mountpoint */
1410 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT,
1411 mountpoint, sizeof (mountpoint),
1412 NULL, NULL, 0, B_FALSE) != 0) {
1413 /* no mountpoint */
1414 continue;
1415 }
1416
1417 /* mountpoint must be a path */
1418 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
1419 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1420 /*
1421 * Search mmttab for mountpoint
1422 */
1423
1424 if (get_legacy_mountpoint(path, dataset,
1425 ZFS_MAXPROPLEN, mountpoint,
1426 ZFS_MAXPROPLEN) == 0) {
1427 ret = 1;
1428 break;
1429 }
1430 continue;
1431 }
1432
1433 /* canmount must be set */
1434 canmount[0] = '\0';
1435 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount,
1436 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
1437 strcmp(canmount, "off") == 0)
1438 continue;
1439
1440 /*
1441 * have a mountable handle but want to skip those marked none
1442 * and legacy
1443 */
1444 if (strcmp(mountpoint, path) == 0) {
1445 dp = (char *)zfs_get_name(cb.cb_handles[i]);
1446 if (dp != NULL) {
1447 if (datasetp != NULL)
1448 (void) strcpy(datasetp, dp);
1449 if (mountpointp != NULL)
1450 (void) strcpy(mountpointp, mountpoint);
1451 ret = 1;
1452 }
1453 break;
1454 }
1455
1456 }
1457
1458 return (ret);
1459 }
1460
1461 /*
1462 * This method builds values for "sharesmb" property from the
1463 * nvlist argument. The values are returned in sharesmb_val variable.
1464 */
1465 static int
1466 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val)
1467 {
1468 char cur_val[MAXPATHLEN];
1469 char *name, *val;
1470 nvpair_t *cur;
1471 int err = 0;
1472
1473 cur = nvlist_next_nvpair(nvl, NULL);
1474 while (cur != NULL) {
1475 name = nvpair_name(cur);
1476 err = nvpair_value_string(cur, &val);
1477 if ((err != 0) || (name == NULL) || (val == NULL))
1478 return (-1);
1479
1480 (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val);
1481 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1482
1483 cur = nvlist_next_nvpair(nvl, cur);
1484 }
1485
1486 return (0);
1487 }
1488
1489 /*
1490 * This method builds values for "sharesmb" property from values
1491 * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1492 * method are passed in sharesmb_val. If a existing property is already
1493 * set via sa_zfs_sprint_new_prop method, then they are not appended
1494 * to the sharesmb_val string. The returned sharesmb_val string is a combination
1495 * of new and existing values for 'sharesmb' property.
1496 */
1497 static int
1498 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val)
1499 {
1500 char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN];
1501 char *token, *last, *value;
1502
1503 if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts,
1504 sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0)
1505 return (-1);
1506
1507 if (strstr(shareopts, "=") == NULL)
1508 return (0);
1509
1510 for (token = strtok_r(shareopts, ",", &last); token != NULL;
1511 token = strtok_r(NULL, ",", &last)) {
1512 value = strchr(token, '=');
1513 if (value == NULL)
1514 return (-1);
1515 *value++ = '\0';
1516
1517 (void) snprintf(cur_val, MAXPATHLEN, "%s=", token);
1518 if (strstr(sharesmb_val, cur_val) == NULL) {
1519 (void) strlcat(cur_val, value, MAXPATHLEN);
1520 (void) strlcat(cur_val, ",", MAXPATHLEN);
1521 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1522 }
1523 }
1524
1525 return (0);
1526 }
1527
1528 /*
1529 * Sets the share properties on a ZFS share. For now, this method sets only
1530 * the "sharesmb" property.
1531 *
1532 * This method includes building a comma seperated name-value string to be
1533 * set on the "sharesmb" property of a ZFS share. This name-value string is
1534 * build in 2 steps:
1535 * - New property values given as name-value pair are set first.
1536 * - Existing optionset properties, which are not part of the new properties
1537 * passed in step 1, are appended to the newly set properties.
1538 */
1539 int
1540 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl)
1541 {
1542 zfs_handle_t *z_fs;
1543 libzfs_handle_t *z_lib;
1544 char sharesmb_val[MAXPATHLEN];
1545 char *dataset, *lastcomma;
1546
1547 if (nvlist_empty(nvl))
1548 return (0);
1549
1550 if ((handle == NULL) || (path == NULL))
1551 return (-1);
1552
1553 if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL)
1554 return (-1);
1555
1556 if ((z_lib = libzfs_init()) == NULL) {
1557 free(dataset);
1558 return (-1);
1559 }
1560
1561 z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET);
1562 if (z_fs == NULL) {
1563 free(dataset);
1564 libzfs_fini(z_lib);
1565 return (-1);
1566 }
1567
1568 bzero(sharesmb_val, MAXPATHLEN);
1569 if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) {
1570 free(dataset);
1571 zfs_close(z_fs);
1572 libzfs_fini(z_lib);
1573 return (-1);
1574 }
1575
1576 if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) {
1577 free(dataset);
1578 zfs_close(z_fs);
1579 libzfs_fini(z_lib);
1580 return (-1);
1581 }
1582
1583 lastcomma = strrchr(sharesmb_val, ',');
1584 if ((lastcomma != NULL) && (lastcomma[1] == '\0'))
1585 *lastcomma = '\0';
1586
1587 (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB),
1588 sharesmb_val);
1589 free(dataset);
1590 zfs_close(z_fs);
1591 libzfs_fini(z_lib);
1592
1593 return (0);
1594 }
|
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 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2013 RackTop Systems.
26 */
27
28 #include <stdio.h>
29 #include <libzfs.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <errno.h>
33 #include <libshare.h>
34 #include "libshare_impl.h"
35 #include <libintl.h>
36 #include <sys/mnttab.h>
37 #include <sys/mntent.h>
38
39 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
40 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
41 extern char *sa_fstype(char *);
42 extern void set_node_attr(void *, char *, char *);
43 extern boolean_t sa_is_share(void *);
44 extern void sa_update_sharetab_ts(sa_handle_t);
45
46 /*
47 * File system specific code for ZFS. The original code was stolen
48 * from the "zfs" command and modified to better suit this library's
49 * usage.
50 */
51
52 typedef struct get_all_cbdata {
53 zfs_handle_t **cb_handles;
54 size_t cb_alloc;
55 size_t cb_used;
56 uint_t cb_types;
57 } get_all_cbdata_t;
58
59 /*
60 * sa_zfs_init(handle)
61 *
62 * Initialize an access handle into libzfs. The handle needs to stay
63 * around until sa_zfs_fini() in order to maintain the cache of
64 * mounts.
65 */
66
67 int
68 sa_zfs_init(sa_handle_t handle)
69 {
70 handle->zfs_libhandle = libzfs_init();
71 if (handle->zfs_libhandle != NULL) {
72 libzfs_print_on_error(handle->zfs_libhandle, B_TRUE);
73 return (B_TRUE);
74 }
75 return (B_FALSE);
76 }
77
78 /*
79 * sa_zfs_fini(handle)
80 *
81 * cleanup data structures and the libzfs handle used for accessing
82 * zfs file share info.
83 */
84
85 void
86 sa_zfs_fini(sa_handle_t handle)
87 {
88 if (handle->zfs_libhandle != NULL) {
89 if (handle->zfs_list != NULL) {
90 zfs_handle_t **zhp = handle->zfs_list;
91 size_t i;
92
93 /*
94 * Contents of zfs_list need to be freed so we
95 * don't lose ZFS handles.
96 */
97 for (i = 0; i < handle->zfs_list_count; i++) {
98 zfs_close(zhp[i]);
99 }
100 free(handle->zfs_list);
101 handle->zfs_list = NULL;
102 handle->zfs_list_count = 0;
103 }
104
105 libzfs_fini(handle->zfs_libhandle);
106 handle->zfs_libhandle = NULL;
107 }
108 }
109
110 /*
111 * get_one_filesystem(zfs_handle_t, data)
112 *
113 * an iterator function called while iterating through the ZFS
114 * root. It accumulates into an array of file system handles that can
115 * be used to derive info about those file systems.
116 *
117 * Note that as this function is called, we close all zhp handles that
118 * are not going to be places into the cp_handles list. We don't want
119 * to close the ones we are keeping, but all others would be leaked if
120 * not closed here.
121 */
122
123 static int
124 get_one_filesystem(zfs_handle_t *zhp, void *data)
125 {
126 get_all_cbdata_t *cbp = data;
165 }
166
167 cbp->cb_handles = handles;
168 }
169
170 cbp->cb_handles[cbp->cb_used++] = zhp;
171
172 return (0);
173 }
174
175 /*
176 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
177 *
178 * iterate through all ZFS file systems starting at the root. Returns
179 * a count and an array of handle pointers. Allocating is only done
180 * once. The caller does not need to free since it will be done at
181 * sa_zfs_fini() time.
182 */
183
184 static void
185 get_all_filesystems(sa_handle_t handle,
186 zfs_handle_t ***fslist, size_t *count)
187 {
188 get_all_cbdata_t cb = { 0 };
189 cb.cb_types = ZFS_TYPE_FILESYSTEM;
190
191 if (handle->zfs_list != NULL) {
192 *fslist = handle->zfs_list;
193 *count = handle->zfs_list_count;
194 return;
195 }
196
197 (void) zfs_iter_root(handle->zfs_libhandle,
198 get_one_filesystem, &cb);
199
200 handle->zfs_list = *fslist = cb.cb_handles;
201 handle->zfs_list_count = *count = cb.cb_used;
202 }
203
204 /*
205 * mountpoint_compare(a, b)
206 *
207 * compares the mountpoint on two zfs file systems handles.
208 * returns values following strcmp() model.
209 */
210
211 static int
212 mountpoint_compare(const void *a, const void *b)
213 {
214 zfs_handle_t **za = (zfs_handle_t **)a;
215 zfs_handle_t **zb = (zfs_handle_t **)b;
216 char mounta[MAXPATHLEN];
217 char mountb[MAXPATHLEN];
218
219 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
220 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
221 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
243
244 if (entry.mnt_fstype == NULL ||
245 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
246 continue;
247
248 if (strcmp(entry.mnt_mountp, path) == 0) {
249 if (mlen > 0)
250 (void) strlcpy(mountpoint, entry.mnt_mountp,
251 mlen);
252 if (dlen > 0)
253 (void) strlcpy(dataset, entry.mnt_special,
254 dlen);
255 break;
256 }
257 }
258 (void) fclose(fp);
259 return (1);
260 }
261
262 /*
263 * get_zfs_dataset(handle, path)
264 *
265 * get the name of the ZFS dataset the path is equivalent to. The
266 * dataset name is used for get/set of ZFS properties since libzfs
267 * requires a dataset to do a zfs_open().
268 */
269
270 static char *
271 get_zfs_dataset(sa_handle_t handle, char *path,
272 boolean_t search_mnttab)
273 {
274 size_t i, count = 0;
275 char *dataset = NULL;
276 zfs_handle_t **zlist;
277 char mountpoint[ZFS_MAXPROPLEN];
278 char canmount[ZFS_MAXPROPLEN];
279
280 get_all_filesystems(handle, &zlist, &count);
281 qsort(zlist, count, sizeof (void *), mountpoint_compare);
282 for (i = 0; i < count; i++) {
283 /* must have a mountpoint */
284 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint,
285 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
286 /* no mountpoint */
287 continue;
288 }
289
290 /* mountpoint must be a path */
291 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
292 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
293 /*
294 * Search mmttab for mountpoint and get dataset.
295 */
296
297 if (search_mnttab == B_TRUE &&
298 get_legacy_mountpoint(path, mountpoint,
299 sizeof (mountpoint), NULL, 0) == 0) {
300 dataset = mountpoint;
317 if (strcmp(mountpoint, path) == 0) {
318 dataset = (char *)zfs_get_name(zlist[i]);
319 break;
320 }
321
322 }
323
324 if (dataset != NULL)
325 dataset = strdup(dataset);
326
327 return (dataset);
328 }
329
330 /*
331 * get_zfs_property(dataset, property)
332 *
333 * Get the file system property specified from the ZFS dataset.
334 */
335
336 static char *
337 get_zfs_property(sa_handle_t handle, char *dataset, zfs_prop_t property)
338 {
339 zfs_handle_t *z_fs;
340 char shareopts[ZFS_MAXPROPLEN];
341
342 z_fs = zfs_open(handle->zfs_libhandle, dataset, ZFS_TYPE_FILESYSTEM);
343 if (z_fs != NULL) {
344 if (zfs_prop_get(z_fs, property, shareopts,
345 sizeof (shareopts), NULL, NULL, 0,
346 B_FALSE) == 0) {
347 zfs_close(z_fs);
348 return (strdup(shareopts));
349 }
350 zfs_close(z_fs);
351 }
352 return (NULL);
353 }
354
355 /*
356 * sa_zfs_is_shared(handle, path)
357 *
358 * Check to see if the ZFS path provided has the sharenfs option set
359 * or not.
360 */
361
362 boolean_t
363 sa_zfs_is_shared(sa_handle_t handle, char *path)
364 {
365 int ret = B_FALSE;
366 char *dataset;
367 zfs_handle_t *z_fs = NULL;
368 char shareopts[ZFS_MAXPROPLEN];
369
370 dataset = get_zfs_dataset(handle, path, B_FALSE);
371 if (dataset != NULL) {
372 z_fs = zfs_open(handle->zfs_libhandle, dataset,
373 ZFS_TYPE_FILESYSTEM);
374 if (z_fs != NULL) {
375 if (zfs_prop_get(z_fs, ZFS_PROP_SHARENFS,
376 shareopts, sizeof (shareopts), NULL, NULL,
377 0, B_FALSE) == 0 &&
378 strcmp(shareopts, "off") != 0) {
379 ret = B_TRUE; /* it is shared */
380 }
381 zfs_close(z_fs);
382 }
383 free(dataset);
384 }
385 return (ret);
386 }
387
388 /*
389 * find_or_create_group(handle, groupname, proto, *err)
390 *
391 * While walking the ZFS tree, we need to add shares to a defined
392 * group. If the group doesn't exist, create it first, making sure it
393 * is marked as a ZFS group.
394 *
395 * Note that all ZFS shares are in a subgroup of the top level group
396 * called "zfs".
397 */
398
399 static sa_group_t
400 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
401 {
734 sa_group_t zfsgroup;
735 boolean_t nfs;
736 boolean_t nfs_inherited;
737 boolean_t smb;
738 boolean_t smb_inherited;
739 zfs_handle_t **zlist;
740 char nfsshareopts[ZFS_MAXPROPLEN];
741 char smbshareopts[ZFS_MAXPROPLEN];
742 sa_share_t share;
743 zprop_source_t source;
744 char nfssourcestr[ZFS_MAXPROPLEN];
745 char smbsourcestr[ZFS_MAXPROPLEN];
746 char mountpoint[ZFS_MAXPROPLEN];
747 size_t count = 0, i;
748 libzfs_handle_t *zfs_libhandle;
749 int err = SA_OK;
750
751 /*
752 * If we can't access libzfs, don't bother doing anything.
753 */
754 zfs_libhandle = handle->zfs_libhandle;
755 if (zfs_libhandle == NULL)
756 return (SA_SYSTEM_ERR);
757
758 zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
759 /* Not an error, this could be a legacy condition */
760 if (zfsgroup == NULL)
761 return (SA_OK);
762
763 /*
764 * need to walk the mounted ZFS pools and datasets to
765 * find shares that are possible.
766 */
767 get_all_filesystems(handle, &zlist, &count);
768 qsort(zlist, count, sizeof (void *), mountpoint_compare);
769
770 for (i = 0; i < count; i++) {
771 char *dataset;
772
773 source = ZPROP_SRC_ALL;
774 /* If no mountpoint, skip. */
775 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT,
776 mountpoint, sizeof (mountpoint), NULL, NULL, 0,
777 B_FALSE) != 0)
778 continue;
779
780 /*
781 * zfs_get_name value must not be freed. It is just a
782 * pointer to a value in the handle.
783 */
784 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL)
785 continue;
786
787 /*
903
904 /*
905 * sa_zfs_set_sharenfs(group, path, on)
906 *
907 * Update the "sharenfs" property on the path. If on is true, then set
908 * to the properties on the group or "on" if no properties are
909 * defined. Set to "off" if on is false.
910 */
911
912 int
913 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
914 {
915 int ret = SA_NOT_IMPLEMENTED;
916 char *command;
917
918 command = malloc(ZFS_MAXPROPLEN * 2);
919 if (command != NULL) {
920 char *opts = NULL;
921 char *dataset = NULL;
922 FILE *pfile;
923 sa_handle_t handle;
924 /* for now, NFS is always available for "zfs" */
925 if (on) {
926 opts = sa_proto_legacy_format("nfs", group, 1);
927 if (opts != NULL && strlen(opts) == 0) {
928 free(opts);
929 opts = strdup("on");
930 }
931 }
932
933 handle = sa_find_group_handle(group);
934 assert(handle != NULL);
935 if (handle != NULL)
936 dataset = get_zfs_dataset(handle, path, B_FALSE);
937 else
938 ret = SA_SYSTEM_ERR;
939
940 if (dataset != NULL) {
941 (void) snprintf(command, ZFS_MAXPROPLEN * 2,
942 "%s set sharenfs=\"%s\" %s", COMMAND,
943 opts != NULL ? opts : "off", dataset);
944 pfile = popen(command, "r");
945 if (pfile != NULL) {
946 ret = pclose(pfile);
947 if (ret != 0)
948 ret = SA_SYSTEM_ERR;
949 }
950 }
951 if (opts != NULL)
952 free(opts);
953 if (dataset != NULL)
954 free(dataset);
955 free(command);
956 }
1014 * to the properties on the group or "on" if no properties are
1015 * defined. Set to "off" if on is false.
1016 */
1017
1018 int
1019 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
1020 {
1021 int ret = SA_NOT_IMPLEMENTED;
1022 char *command;
1023 sa_share_t share;
1024
1025 /* In case SMB not enabled */
1026 if (sa_get_optionset(group, "smb") == NULL)
1027 return (SA_NOT_SUPPORTED);
1028
1029 command = malloc(ZFS_MAXPROPLEN * 2);
1030 if (command != NULL) {
1031 char *opts = NULL;
1032 char *dataset = NULL;
1033 FILE *pfile;
1034 sa_handle_t handle;
1035
1036 if (on) {
1037 char *newopt;
1038
1039 share = sa_get_share(group, NULL);
1040 opts = sa_proto_legacy_format("smb", share, 1);
1041 if (opts != NULL && strlen(opts) == 0) {
1042 free(opts);
1043 opts = strdup("on");
1044 }
1045 newopt = add_resources(opts, share);
1046 free(opts);
1047 opts = newopt;
1048 }
1049
1050 handle = sa_find_group_handle(group);
1051 assert(handle != NULL);
1052 if (handle != NULL)
1053 dataset = get_zfs_dataset(handle, path, B_FALSE);
1054 else
1055 ret = SA_SYSTEM_ERR;
1056
1057 if (dataset != NULL) {
1058 (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1059 "echo %s set sharesmb=\"%s\" %s", COMMAND,
1060 opts != NULL ? opts : "off", dataset);
1061 pfile = popen(command, "r");
1062 if (pfile != NULL) {
1063 ret = pclose(pfile);
1064 if (ret != 0)
1065 ret = SA_SYSTEM_ERR;
1066 }
1067 }
1068 if (opts != NULL)
1069 free(opts);
1070 if (dataset != NULL)
1071 free(dataset);
1072 free(command);
1073 }
1097 parent = group;
1098
1099 if (parent != NULL) {
1100 command = malloc(ZFS_MAXPROPLEN * 2);
1101 if (command == NULL)
1102 return (SA_NO_MEMORY);
1103
1104 *command = '\0';
1105 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL;
1106 protopt = sa_get_next_optionset(protopt)) {
1107
1108 char *proto = sa_get_optionset_attr(protopt, "type");
1109 char *path;
1110 char *dataset = NULL;
1111 char *zfsopts = NULL;
1112
1113 if (sa_is_share(group)) {
1114 path = sa_get_share_attr((sa_share_t)group,
1115 "path");
1116 if (path != NULL) {
1117 sa_handle_t handle;
1118
1119 handle = sa_find_group_handle(
1120 group);
1121 if (handle != NULL)
1122 dataset = get_zfs_dataset(
1123 handle, path, B_FALSE);
1124 else
1125 ret = SA_SYSTEM_ERR;
1126
1127 sa_free_attr_string(path);
1128 }
1129 } else {
1130 dataset = sa_get_group_attr(group, "name");
1131 }
1132 /* update only when there is an optstring found */
1133 doupdate = 0;
1134 if (proto != NULL && dataset != NULL) {
1135 sa_handle_t handle;
1136
1137 optstring = sa_proto_legacy_format(proto,
1138 group, 1);
1139 handle = sa_find_group_handle(group);
1140 zfsopts = get_zfs_property(handle, dataset,
1141 ZFS_PROP_SHARENFS);
1142
1143 if (optstring != NULL && zfsopts != NULL) {
1144 if (strcmp(optstring, zfsopts) != 0)
1145 doupdate++;
1146 }
1147 if (doupdate) {
1148 if (optstring != NULL &&
1149 strlen(optstring) > 0) {
1150 (void) snprintf(command,
1151 ZFS_MAXPROPLEN * 2,
1152 "%s set share%s=%s %s",
1153 COMMAND, proto,
1154 optstring, dataset);
1155 } else {
1156 (void) snprintf(command,
1157 ZFS_MAXPROPLEN * 2,
1158 "%s set share%s=on %s",
1159 COMMAND, proto,
1160 dataset);
1178 free(optstring);
1179 if (zfsopts != NULL)
1180 free(zfsopts);
1181 }
1182 if (proto != NULL)
1183 sa_free_attr_string(proto);
1184 if (dataset != NULL)
1185 free(dataset);
1186 }
1187 free(command);
1188 }
1189 return (ret);
1190 }
1191
1192 /*
1193 * sa_group_is_zfs(group)
1194 *
1195 * Given the group, determine if the zfs attribute is set.
1196 */
1197
1198 boolean_t
1199 sa_group_is_zfs(sa_group_t group)
1200 {
1201 char *zfs;
1202 int ret = B_FALSE;
1203
1204 zfs = sa_get_group_attr(group, "zfs");
1205 if (zfs != NULL) {
1206 ret = B_TRUE;
1207 sa_free_attr_string(zfs);
1208 }
1209 return (ret);
1210 }
1211
1212 /*
1213 * sa_path_is_zfs(path)
1214 *
1215 * Check to see if the file system path represents is of type "zfs".
1216 */
1217
1218 boolean_t
1219 sa_path_is_zfs(char *path)
1220 {
1221 char *fstype;
1222 int ret = B_FALSE;
1223
1224 fstype = sa_fstype(path);
1225 if (fstype != NULL && strcmp(fstype, "zfs") == 0)
1226 ret = B_TRUE;
1227 if (fstype != NULL)
1228 sa_free_fstype(fstype);
1229 return (ret);
1230 }
1231
1232 int
1233 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
1234 {
1235 char *path;
1236
1237 /* Make sure path is valid */
1238
1239 path = sa_get_share_attr(share, "path");
1240 if (path != NULL) {
1241 (void) memset(sh, 0, sizeof (sh));
1242 (void) sa_fillshare(share, proto, sh);
1243 sa_free_attr_string(path);
1244 return (0);
1245 } else
1246 return (1);
1247 }
1248
1249 #define SMAX(i, j) \
1250 if ((j) > (i)) { \
1251 (i) = (j); \
1252 }
1253
1254 int
1255 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh,
1256 void *exportdata, zfs_share_op_t operation)
1257 {
1258 sa_group_t group;
1259 sa_handle_t handle;
1260 char *dataset;
1261 int err = EINVAL;
1262 int i, j;
1263 char newpath[MAXPATHLEN];
1264 char *pathp;
1265 char *resource_name;
1266
1267 /*
1268 * First find the dataset name
1269 */
1270 if ((group = sa_get_parent_group(share)) == NULL) {
1271 return (EINVAL);
1272 }
1273 if ((handle = sa_find_group_handle(group)) == NULL) {
1274 return (EINVAL);
1275 }
1276
1277 /*
1278 * If get_zfs_dataset fails, see if it is a subdirectory
1279 */
1280
1281 pathp = path;
1282 while ((dataset = get_zfs_dataset(handle, pathp, B_TRUE)) == NULL) {
1283 char *p;
1284
1285 if (pathp == path) {
1286 (void) strlcpy(newpath, path, sizeof (newpath));
1287 pathp = newpath;
1288 }
1289
1290 /*
1291 * Make sure only one leading '/' This condition came
1292 * about when using HAStoragePlus which insisted on
1293 * putting an extra leading '/' in the ZFS path
1294 * name. The problem is fixed in other areas, but this
1295 * will catch any other ways that a double slash might
1296 * get introduced.
1297 */
1298 while (*pathp == '/' && *(pathp + 1) == '/')
1299 pathp++;
1300
1301 /*
1302 * chop off part of path, but if we are at root then
1303 * make sure path is a /
1304 */
1305 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) {
1306 if (pathp == p) {
1307 *(p + 1) = '\0'; /* skip over /, root case */
1308 } else {
1309 *p = '\0';
1310 }
1311 } else {
1312 return (EINVAL);
1313 }
1314 }
1315
1316 i = (sh->sh_path ? strlen(sh->sh_path) : 0);
1317 sh->sh_size = i;
1318
1319 j = (sh->sh_res ? strlen(sh->sh_res) : 0);
1320 sh->sh_size += j;
1321 SMAX(i, j);
1322
1323 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
1324 sh->sh_size += j;
1325 SMAX(i, j);
1326
1327 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
1328 sh->sh_size += j;
1329 SMAX(i, j);
1330
1331 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
1332 sh->sh_size += j;
1333 SMAX(i, j);
1334
1335 resource_name = sa_get_resource_attr(resource, "name");
1336
1337 err = zfs_deleg_share_nfs(handle->zfs_libhandle, dataset, path,
1338 resource_name, exportdata, sh, i, operation);
1339 if (err == SA_OK)
1340 sa_update_sharetab_ts(handle);
1341 else
1342 err = errno;
1343 if (resource_name != NULL)
1344 sa_free_attr_string(resource_name);
1345
1346 free(dataset);
1347 return (err);
1348 }
1349
1350 /*
1351 * sa_get_zfs_handle(handle)
1352 *
1353 * Given an sa_handle_t, return the libzfs_handle_t *. This is only
1354 * used internally by libzfs. Needed in order to avoid including
1355 * libshare_impl.h in libzfs.
1356 */
1357
1358 libzfs_handle_t *
1359 sa_get_zfs_handle(sa_handle_t handle)
1360 {
1361 return (handle->zfs_libhandle);
1362 }
1363
1364 /*
1365 * This method builds values for "sharesmb" property from the
1366 * nvlist argument. The values are returned in sharesmb_val variable.
1367 */
1368 static int
1369 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val)
1370 {
1371 char cur_val[ZFS_MAXPROPLEN];
1372 char *name, *val;
1373 nvpair_t *cur;
1374 int err = 0;
1375
1376 cur = nvlist_next_nvpair(nvl, NULL);
1377 while (cur != NULL) {
1378 name = nvpair_name(cur);
1379 err = nvpair_value_string(cur, &val);
1380 if ((err != 0) || (name == NULL) || (val == NULL))
1381 return (-1);
1382
1383 (void) snprintf(cur_val, ZFS_MAXPROPLEN, "%s=%s,", name, val);
1384 (void) strlcat(sharesmb_val, cur_val, ZFS_MAXPROPLEN);
1385
1386 cur = nvlist_next_nvpair(nvl, cur);
1387 }
1388
1389 return (0);
1390 }
1391
1392 /*
1393 * This method builds values for "sharesmb" property from values
1394 * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1395 * method are passed in sharesmb_val. If a existing property is already
1396 * set via sa_zfs_sprint_new_prop method, then they are not appended
1397 * to the sharesmb_val string. The returned sharesmb_val string is a combination
1398 * of new and existing values for 'sharesmb' property.
1399 */
1400 static int
1401 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val)
1402 {
1403 char shareopts[ZFS_MAXPROPLEN], cur_val[ZFS_MAXPROPLEN];
1404 char *token, *last, *value;
1405
1406 if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts,
1407 sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0)
1408 return (-1);
1409
1410 if (strstr(shareopts, "=") == NULL)
1411 return (0);
1412
1413 for (token = strtok_r(shareopts, ",", &last); token != NULL;
1414 token = strtok_r(NULL, ",", &last)) {
1415 value = strchr(token, '=');
1416 if (value == NULL)
1417 return (-1);
1418 *value++ = '\0';
1419
1420 (void) snprintf(cur_val, ZFS_MAXPROPLEN, "%s=", token);
1421 if (strstr(sharesmb_val, cur_val) == NULL) {
1422 (void) strlcat(cur_val, value, ZFS_MAXPROPLEN);
1423 (void) strlcat(cur_val, ",", ZFS_MAXPROPLEN);
1424 (void) strlcat(sharesmb_val, cur_val, ZFS_MAXPROPLEN);
1425 }
1426 }
1427
1428 return (0);
1429 }
1430
1431 /*
1432 * Sets the share properties on a ZFS share. For now, this method sets only
1433 * the "sharesmb" property.
1434 *
1435 * This method includes building a comma seperated name-value string to be
1436 * set on the "sharesmb" property of a ZFS share. This name-value string is
1437 * build in 2 steps:
1438 * - New property values given as name-value pair are set first.
1439 * - Existing optionset properties, which are not part of the new properties
1440 * passed in step 1, are appended to the newly set properties.
1441 */
1442 int
1443 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl)
1444 {
1445 zfs_handle_t *z_fs;
1446 char sharesmb_val[ZFS_MAXPROPLEN];
1447 char *dataset, *lastcomma;
1448
1449 if (nvlist_empty(nvl))
1450 return (0);
1451
1452 if ((handle == NULL) || (path == NULL))
1453 return (-1);
1454
1455 if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL)
1456 return (-1);
1457
1458 z_fs = zfs_open(handle->zfs_libhandle, dataset, ZFS_TYPE_DATASET);
1459 if (z_fs == NULL) {
1460 free(dataset);
1461 return (-1);
1462 }
1463
1464 bzero(sharesmb_val, ZFS_MAXPROPLEN);
1465 if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) {
1466 free(dataset);
1467 zfs_close(z_fs);
1468 return (-1);
1469 }
1470
1471 if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) {
1472 free(dataset);
1473 zfs_close(z_fs);
1474 return (-1);
1475 }
1476
1477 lastcomma = strrchr(sharesmb_val, ',');
1478 if ((lastcomma != NULL) && (lastcomma[1] == '\0'))
1479 *lastcomma = '\0';
1480
1481 (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB),
1482 sharesmb_val);
1483 free(dataset);
1484 zfs_close(z_fs);
1485
1486 return (0);
1487 }
|