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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "libfsmgt.h" 30 #include <libzfs.h> 31 #include <string.h> 32 #include <libshare.h> 33 #include "libshare_impl.h" 34 35 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 36 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 37 extern char *sa_fstype(char *); 38 extern void set_node_attr(void *, char *, char *); 39 extern int sa_is_share(void *); 40 /* 41 * File system specific code for ZFS 42 */ 43 44 /* 45 * get_zfs_dataset(path) 46 * 47 * get the name of the ZFS dataset the path is equivalent to. The 48 * dataset name is used for get/set of ZFS properties since libzfs 49 * requires a dataset to do a zfs_open(). 50 */ 51 52 static char * 53 get_zfs_dataset(char *path) 54 { 55 fs_mntlist_t *list; 56 fs_mntlist_t *cur; 57 int err; 58 char *dataset = NULL; 59 60 list = fs_get_filtered_mount_list(NULL, NULL, "zfs", NULL, 61 NULL, 0, &err); 62 for (cur = list; cur != NULL; cur = cur->next) { 63 if (strcmp(path, cur->mountp) == 0 || 64 strncmp(path, cur->mountp, strlen(cur->mountp)) == 0) { 65 /* 66 * we want the longest resource so keep trying. This 67 * check avoids dropping out on a partial match. ZFS 68 * resources are ordered when mounted in order to 69 * ensure inheritence of properties. 70 */ 71 dataset = cur->resource; 72 } 73 } 74 if (dataset != NULL) { 75 dataset = strdup(dataset); 76 } 77 fs_free_mount_list(list); 78 return (dataset); 79 } 80 81 /* 82 * get_zfs_property(dataset, property) 83 * 84 * Get the file system property specified from the ZFS dataset. 85 */ 86 87 static char * 88 get_zfs_property(char *dataset, zfs_prop_t property) 89 { 90 zfs_handle_t *handle = NULL; 91 char shareopts[ZFS_MAXPROPLEN]; 92 libzfs_handle_t *libhandle; 93 94 libhandle = libzfs_init(); 95 if (libhandle != NULL) { 96 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 97 if (handle != NULL) { 98 if (zfs_prop_get(handle, property, shareopts, 99 sizeof (shareopts), NULL, NULL, 0, 100 FALSE) == 0) { 101 zfs_close(handle); 102 libzfs_fini(libhandle); 103 return (strdup(shareopts)); 104 } 105 zfs_close(handle); 106 } 107 libzfs_fini(libhandle); 108 } 109 return (NULL); 110 } 111 112 /* 113 * sa_zfs_is_shared(path) 114 * 115 * Check to see if the ZFS path provided has the sharenfs option set 116 * or not. 117 */ 118 119 int 120 sa_zfs_is_shared(char *path) 121 { 122 int ret = 0; 123 char *dataset; 124 zfs_handle_t *handle = NULL; 125 char shareopts[ZFS_MAXPROPLEN]; 126 libzfs_handle_t *libhandle; 127 128 dataset = get_zfs_dataset(path); 129 if (dataset != NULL) { 130 libhandle = libzfs_init(); 131 if (libhandle != NULL) { 132 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 133 if (handle != NULL) { 134 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts, 135 sizeof (shareopts), NULL, NULL, 0, 136 FALSE) == 0 && 137 strcmp(shareopts, "off") != 0) 138 ret = 1; /* it is shared */ 139 zfs_close(handle); 140 } 141 libzfs_fini(libhandle); 142 } 143 free(dataset); 144 } 145 return (ret); 146 } 147 148 /* 149 * find_or_create_group(groupname, proto, *err) 150 * 151 * While walking the ZFS tree, we need to add shares to a defined 152 * group. If the group doesn't exist, create it first, making sure it 153 * is marked as a ZFS group. 154 * 155 * Not that all ZFS shares are in a subgroup of the top level group 156 * "zfs". 157 */ 158 159 static sa_group_t 160 find_or_create_group(char *groupname, char *proto, int *err) 161 { 162 sa_group_t group; 163 sa_optionset_t optionset; 164 int ret = SA_OK; 165 166 /* 167 * we check to see if the "zfs" group exists. Since this 168 * should be the top level group, we don't want the 169 * parent. This is to make sure the zfs group has been created 170 * and to created if it hasn't been. 171 */ 172 group = sa_get_group(groupname); 173 if (group == NULL) { 174 group = sa_create_group(groupname, &ret); 175 if (group != NULL) 176 ret = sa_set_group_attr(group, "zfs", "true"); 177 } 178 if (group != NULL) { 179 if (proto != NULL) { 180 optionset = sa_get_optionset(group, proto); 181 if (optionset == NULL) { 182 optionset = sa_create_optionset(group, proto); 183 } else { 184 char **protolist; 185 int numprotos, i; 186 numprotos = sa_get_protocols(&protolist); 187 for (i = 0; i < numprotos; i++) { 188 optionset = sa_create_optionset(group, protolist[i]); 189 } 190 if (protolist != NULL) 191 free(protolist); 192 } 193 } 194 } 195 if (err != NULL) 196 *err = ret; 197 return (group); 198 } 199 200 /* 201 * sa_get_zfs_shares(groupname) 202 * 203 * Walk the mnttab for all zfs mounts and determine which are 204 * shared. Find or create the appropriate group/sub-group to contain 205 * the shares. 206 * 207 * All shares are in a sub-group that will hold the properties. This 208 * allows representing the inherited property model. 209 */ 210 211 int 212 sa_get_zfs_shares(char *groupname) 213 { 214 sa_group_t group; 215 sa_group_t zfsgroup; 216 int legacy = 0; 217 int err; 218 fs_mntlist_t *list; 219 fs_mntlist_t *cur; 220 zfs_handle_t *handle = NULL; 221 char shareopts[ZFS_MAXPROPLEN]; 222 sa_share_t share; 223 zfs_source_t source; 224 char sourcestr[ZFS_MAXPROPLEN]; 225 libzfs_handle_t *libhandle; 226 227 /* 228 * if we can't access libzfs, don't bother doing anything. 229 */ 230 libhandle = libzfs_init(); 231 if (libhandle == NULL) 232 return (SA_SYSTEM_ERR); 233 234 zfsgroup = find_or_create_group(groupname, "nfs", &err); 235 if (zfsgroup != NULL) { 236 /* 237 * need to walk the mounted ZFS pools and datasets to 238 * find shares that are possible. 239 */ 240 list = fs_get_filtered_mount_list(NULL, NULL, "zfs", NULL, 241 NULL, 0, &err); 242 group = zfsgroup; 243 for (cur = list; cur != NULL; cur = cur->next) { 244 handle = zfs_open(libhandle, cur->resource, 245 ZFS_TYPE_FILESYSTEM); 246 if (handle != NULL) { 247 source = ZFS_SRC_ALL; 248 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts, 249 sizeof (shareopts), &source, sourcestr, 250 ZFS_MAXPROPLEN, 251 FALSE) == 0 && 252 strcmp(shareopts, "off") != 0) { 253 /* it is shared so add to list */ 254 share = sa_find_share(cur->mountp); 255 err = SA_OK; 256 if (share != NULL) { 257 /* 258 * A zfs file system had been shared 259 * through tradiditional methods 260 * (share/dfstab or added to a non-zfs 261 * group. Now it has been added to a 262 * ZFS group via the zfs 263 * command. Remove from previous 264 * config and setup with current 265 * options. 266 */ 267 err = sa_remove_share(share); 268 share = NULL; 269 } 270 if (err == SA_OK) { 271 if (source & ZFS_SRC_INHERITED) { 272 share = _sa_add_share(group, cur->mountp, 273 SA_SHARE_TRANSIENT, 274 &err); 275 } else { 276 group = _sa_create_zfs_group(zfsgroup, 277 cur->resource); 278 set_node_attr(group, "zfs", "true"); 279 share = _sa_add_share(group, cur->mountp, 280 SA_SHARE_TRANSIENT, 281 &err); 282 if (err == SA_OK) { 283 char *options; 284 if (strcmp(shareopts, "on") != 0) { 285 options = strdup(shareopts); 286 if (options != NULL) { 287 err = sa_parse_legacy_options(group, 288 options, 289 "nfs"); 290 free(options); 291 } 292 /* unmark the share's changed state */ 293 set_node_attr(share, "changed", NULL); 294 } 295 } 296 } 297 } 298 } 299 } 300 } 301 if (list != NULL) 302 fs_free_mount_list(list); 303 } 304 if (libhandle != NULL) 305 libzfs_fini(libhandle); 306 return (legacy); 307 } 308 309 #define COMMAND "/usr/sbin/zfs" 310 311 /* 312 * sa_zfs_set_sharenfs(group, path, on) 313 * 314 * Update the "sharenfs" property on the path. If on is true, then set 315 * to the properties on the group or "on" if no properties are 316 * defined. Set to "off" if on is false. 317 */ 318 319 int 320 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 321 { 322 int ret = SA_NOT_IMPLEMENTED; 323 char *command; 324 325 command = malloc(ZFS_MAXPROPLEN * 2); 326 if (command != NULL) { 327 char *opts = NULL; 328 char *dataset; 329 FILE *pfile; 330 /* for now, NFS is always available for "zfs" */ 331 if (on) { 332 opts = sa_proto_legacy_format("nfs", group, 1); 333 if (opts != NULL && strlen(opts) == 0) { 334 free(opts); 335 opts = strdup("on"); 336 } 337 } 338 dataset = get_zfs_dataset(path); 339 if (dataset != NULL) { 340 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 341 "%s set sharenfs=\"%s\" %s", COMMAND, 342 opts != NULL ? opts : "off", 343 dataset); 344 pfile = popen(command, "r"); 345 if (pfile != NULL) { 346 ret = pclose(pfile); 347 if (ret != 0) 348 ret = SA_SYSTEM_ERR; 349 } 350 } 351 if (opts != NULL) 352 free(opts); 353 if (dataset != NULL) 354 free(dataset); 355 free(command); 356 } 357 return (ret); 358 } 359 360 /* 361 * sa_zfs_update(group) 362 * 363 * call back to ZFS to update the share if necessary. 364 * Don't do it if it isn't a real change. 365 */ 366 int 367 sa_zfs_update(sa_group_t group) 368 { 369 sa_optionset_t protopt; 370 sa_group_t parent; 371 char *command; 372 char *optstring; 373 int ret = SA_OK; 374 int doupdate = 0; 375 FILE *pfile; 376 377 if (sa_is_share(group)) 378 parent = sa_get_parent_group(group); 379 else 380 parent = group; 381 382 if (parent != NULL) { 383 command = malloc(ZFS_MAXPROPLEN * 2); 384 if (command == NULL) 385 return (SA_NO_MEMORY); 386 387 *command = '\0'; 388 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 389 protopt = sa_get_next_optionset(protopt)) { 390 391 char *proto = sa_get_optionset_attr(protopt, "type"); 392 char *path; 393 char *dataset = NULL; 394 char *zfsopts = NULL; 395 396 if (sa_is_share(group)) { 397 path = sa_get_share_attr((sa_share_t)group, "path"); 398 if (path != NULL) { 399 dataset = get_zfs_dataset(path); 400 sa_free_attr_string(path); 401 } 402 } else { 403 dataset = sa_get_group_attr(group, "name"); 404 } 405 /* update only when there is an optstring found */ 406 doupdate = 0; 407 if (proto != NULL && dataset != NULL) { 408 optstring = sa_proto_legacy_format(proto, group, 1); 409 zfsopts = get_zfs_property(dataset, ZFS_PROP_SHARENFS); 410 411 if (optstring != NULL && zfsopts != NULL) { 412 if (strcmp(optstring, zfsopts) != 0) 413 doupdate++; 414 } 415 416 if (doupdate) { 417 if (optstring != NULL && strlen(optstring) > 0) { 418 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 419 "%s set sharenfs=%s %s", COMMAND, 420 optstring, dataset); 421 } else { 422 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 423 "%s set sharenfs=on %s", COMMAND, 424 dataset); 425 } 426 pfile = popen(command, "r"); 427 if (pfile != NULL) 428 ret = pclose(pfile); 429 switch (ret) { 430 default: 431 case 1: 432 ret = SA_SYSTEM_ERR; 433 break; 434 case 2: 435 ret = SA_SYNTAX_ERR; 436 break; 437 case 0: 438 break; 439 } 440 } 441 if (optstring != NULL) { 442 free(optstring); 443 } 444 if (zfsopts != NULL) 445 free(zfsopts); 446 } 447 if (proto != NULL) 448 sa_free_attr_string(proto); 449 if (dataset != NULL) 450 free(dataset); 451 } 452 free(command); 453 } 454 return (ret); 455 } 456 457 /* 458 * sa_group_is_zfs(group) 459 * 460 * Given the group, determine if the zfs attribute is set. 461 */ 462 463 int 464 sa_group_is_zfs(sa_group_t group) 465 { 466 char *zfs; 467 int ret = 0; 468 469 zfs = sa_get_group_attr(group, "zfs"); 470 if (zfs != NULL) { 471 ret = 1; 472 sa_free_attr_string(zfs); 473 } 474 return (ret); 475 } 476 477 /* 478 * sa_path_is_zfs(path) 479 * 480 * Check to see if the file system path represents is of type "zfs". 481 */ 482 483 int 484 sa_path_is_zfs(char *path) 485 { 486 char *fstype; 487 int ret = 0; 488 489 fstype = sa_fstype(path); 490 if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 491 ret = 1; 492 } 493 if (fstype != NULL) 494 sa_free_fstype(fstype); 495 return (ret); 496 } 497