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 * Note that all ZFS shares are in a subgroup of the top level group 156 * called "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 176 /* make sure this is flagged as a ZFS group */ 177 if (group != NULL) 178 ret = sa_set_group_attr(group, "zfs", "true"); 179 } 180 if (group != NULL) { 181 if (proto != NULL) { 182 optionset = sa_get_optionset(group, proto); 183 if (optionset == NULL) { 184 optionset = sa_create_optionset(group, proto); 185 } else { 186 char **protolist; 187 int numprotos, i; 188 numprotos = sa_get_protocols(&protolist); 189 for (i = 0; i < numprotos; i++) { 190 optionset = sa_create_optionset(group, protolist[i]); 191 } 192 if (protolist != NULL) 193 free(protolist); 194 } 195 } 196 } 197 if (err != NULL) 198 *err = ret; 199 return (group); 200 } 201 202 /* 203 * find_or_create_zfs_subgroup(groupname, optstring, *err) 204 * 205 * ZFS shares will be in a subgroup of the "zfs" master group. This 206 * function looks to see if the groupname exists and returns it if it 207 * does or else creates a new one with the specified name and returns 208 * that. The "zfs" group will exist before we get here, but we make 209 * sure just in case. 210 * 211 * err must be a valid pointer. 212 */ 213 214 static sa_group_t 215 find_or_create_zfs_subgroup(char *groupname, char *optstring, int *err) 216 { 217 sa_group_t group = NULL; 218 sa_group_t zfs; 219 char *name; 220 char *options; 221 222 /* start with the top-level "zfs" group */ 223 zfs = sa_get_group("zfs"); 224 *err = SA_OK; 225 if (zfs != NULL) { 226 for (group = sa_get_sub_group(zfs); group != NULL; 227 group = sa_get_next_group(group)) { 228 name = sa_get_group_attr(group, "name"); 229 if (name != NULL && strcmp(name, groupname) == 0) { 230 /* have the group so break out of here */ 231 sa_free_attr_string(name); 232 break; 233 } 234 if (name != NULL) 235 sa_free_attr_string(name); 236 } 237 238 if (group == NULL) { 239 /* need to create the sub-group since it doesn't exist */ 240 group = _sa_create_zfs_group(zfs, groupname); 241 if (group != NULL) { 242 set_node_attr(group, "zfs", "true"); 243 } 244 if (strcmp(optstring, "on") == 0) 245 optstring = "rw"; 246 if (group != NULL) { 247 options = strdup(optstring); 248 if (options != NULL) { 249 *err = sa_parse_legacy_options(group, options, "nfs"); 250 free(options); 251 } else { 252 *err = SA_NO_MEMORY; 253 } 254 } 255 } 256 } 257 return (group); 258 } 259 260 /* 261 * sa_get_zfs_shares(groupname) 262 * 263 * Walk the mnttab for all zfs mounts and determine which are 264 * shared. Find or create the appropriate group/sub-group to contain 265 * the shares. 266 * 267 * All shares are in a sub-group that will hold the properties. This 268 * allows representing the inherited property model. 269 */ 270 271 int 272 sa_get_zfs_shares(char *groupname) 273 { 274 sa_group_t group; 275 sa_group_t zfsgroup; 276 int legacy = 0; 277 int err; 278 fs_mntlist_t *list; 279 fs_mntlist_t *cur; 280 zfs_handle_t *handle = NULL; 281 char shareopts[ZFS_MAXPROPLEN]; 282 sa_share_t share; 283 zfs_source_t source; 284 char sourcestr[ZFS_MAXPROPLEN]; 285 libzfs_handle_t *libhandle; 286 char *options; 287 288 /* 289 * if we can't access libzfs, don't bother doing anything. 290 */ 291 libhandle = libzfs_init(); 292 if (libhandle == NULL) 293 return (SA_SYSTEM_ERR); 294 295 zfsgroup = find_or_create_group(groupname, "nfs", &err); 296 if (zfsgroup != NULL) { 297 /* 298 * need to walk the mounted ZFS pools and datasets to 299 * find shares that are possible. 300 */ 301 list = fs_get_filtered_mount_list(NULL, NULL, "zfs", NULL, 302 NULL, 0, &err); 303 group = zfsgroup; 304 for (cur = list; cur != NULL; cur = cur->next) { 305 handle = zfs_open(libhandle, cur->resource, 306 ZFS_TYPE_FILESYSTEM); 307 if (handle != NULL) { 308 source = ZFS_SRC_ALL; 309 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts, 310 sizeof (shareopts), &source, sourcestr, 311 ZFS_MAXPROPLEN, 312 FALSE) == 0 && 313 strcmp(shareopts, "off") != 0) { 314 /* it is shared so add to list */ 315 share = sa_find_share(cur->mountp); 316 err = SA_OK; 317 if (share != NULL) { 318 /* 319 * A zfs file system had been shared 320 * through tradiditional methods 321 * (share/dfstab or added to a non-zfs 322 * group. Now it has been added to a 323 * ZFS group via the zfs 324 * command. Remove from previous 325 * config and setup with current 326 * options. 327 */ 328 err = sa_remove_share(share); 329 share = NULL; 330 } 331 if (err == SA_OK) { 332 if (source & ZFS_SRC_INHERITED) { 333 int doshopt = 0; 334 /* 335 * Need to find the "real" parent 336 * sub-group. It may not be mounted, 337 * but it was identified in the 338 * "sourcestr" variable. The real 339 * parent not mounted can occur if 340 * "canmount=off and sharenfs=on". 341 */ 342 group = find_or_create_zfs_subgroup(sourcestr, 343 shareopts, 344 &doshopt); 345 if (group != NULL) { 346 share = _sa_add_share(group, cur->mountp, 347 SA_SHARE_TRANSIENT, 348 &err); 349 /* 350 * some options may only be on 351 * shares. If the opt string 352 * contains one of those, we 353 * put it just on the share. 354 */ 355 if (share != NULL && 356 doshopt == SA_PROP_SHARE_ONLY) { 357 options = strdup(shareopts); 358 if (options != NULL) { 359 err = sa_parse_legacy_options(share, 360 options, "nfs"); 361 free(options); 362 } 363 } 364 } else { 365 err = SA_NO_MEMORY; 366 } 367 } else { 368 /* 369 * this is a sub-group that actually 370 * contains the sharenfs property as 371 * opposed to a share that inherited. 372 */ 373 group = _sa_create_zfs_group(zfsgroup, 374 cur->resource); 375 set_node_attr(group, "zfs", "true"); 376 share = _sa_add_share(group, cur->mountp, 377 SA_SHARE_TRANSIENT, 378 &err); 379 if (err == SA_OK) { 380 if (strcmp(shareopts, "on") != 0) { 381 options = strdup(shareopts); 382 if (options != NULL) { 383 err = sa_parse_legacy_options(group, 384 options, 385 "nfs"); 386 free(options); 387 } 388 if (err == SA_PROP_SHARE_ONLY) { 389 /* 390 * Same as above, some 391 * properties may only be on 392 * shares, but due to the ZFS 393 * sub-groups being 394 * artificial, we sometimes 395 * get this and have to deal 396 * with it. We do it by 397 * attempting to put it on the 398 * share. 399 */ 400 options = strdup(shareopts); 401 if (options != NULL) 402 err = sa_parse_legacy_options( 403 share, 404 options, 405 "nfs"); 406 free(options); 407 } 408 /* unmark the share's changed state */ 409 set_node_attr(share, "changed", NULL); 410 } 411 } 412 } 413 } 414 } 415 } 416 } 417 if (list != NULL) 418 fs_free_mount_list(list); 419 } 420 if (libhandle != NULL) 421 libzfs_fini(libhandle); 422 return (legacy); 423 } 424 425 #define COMMAND "/usr/sbin/zfs" 426 427 /* 428 * sa_zfs_set_sharenfs(group, path, on) 429 * 430 * Update the "sharenfs" property on the path. If on is true, then set 431 * to the properties on the group or "on" if no properties are 432 * defined. Set to "off" if on is false. 433 */ 434 435 int 436 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 437 { 438 int ret = SA_NOT_IMPLEMENTED; 439 char *command; 440 441 command = malloc(ZFS_MAXPROPLEN * 2); 442 if (command != NULL) { 443 char *opts = NULL; 444 char *dataset; 445 FILE *pfile; 446 /* for now, NFS is always available for "zfs" */ 447 if (on) { 448 opts = sa_proto_legacy_format("nfs", group, 1); 449 if (opts != NULL && strlen(opts) == 0) { 450 free(opts); 451 opts = strdup("on"); 452 } 453 } 454 dataset = get_zfs_dataset(path); 455 if (dataset != NULL) { 456 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 457 "%s set sharenfs=\"%s\" %s", COMMAND, 458 opts != NULL ? opts : "off", 459 dataset); 460 pfile = popen(command, "r"); 461 if (pfile != NULL) { 462 ret = pclose(pfile); 463 if (ret != 0) 464 ret = SA_SYSTEM_ERR; 465 } 466 } 467 if (opts != NULL) 468 free(opts); 469 if (dataset != NULL) 470 free(dataset); 471 free(command); 472 } 473 return (ret); 474 } 475 476 /* 477 * sa_zfs_update(group) 478 * 479 * call back to ZFS to update the share if necessary. 480 * Don't do it if it isn't a real change. 481 */ 482 int 483 sa_zfs_update(sa_group_t group) 484 { 485 sa_optionset_t protopt; 486 sa_group_t parent; 487 char *command; 488 char *optstring; 489 int ret = SA_OK; 490 int doupdate = 0; 491 FILE *pfile; 492 493 if (sa_is_share(group)) 494 parent = sa_get_parent_group(group); 495 else 496 parent = group; 497 498 if (parent != NULL) { 499 command = malloc(ZFS_MAXPROPLEN * 2); 500 if (command == NULL) 501 return (SA_NO_MEMORY); 502 503 *command = '\0'; 504 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 505 protopt = sa_get_next_optionset(protopt)) { 506 507 char *proto = sa_get_optionset_attr(protopt, "type"); 508 char *path; 509 char *dataset = NULL; 510 char *zfsopts = NULL; 511 512 if (sa_is_share(group)) { 513 path = sa_get_share_attr((sa_share_t)group, "path"); 514 if (path != NULL) { 515 dataset = get_zfs_dataset(path); 516 sa_free_attr_string(path); 517 } 518 } else { 519 dataset = sa_get_group_attr(group, "name"); 520 } 521 /* update only when there is an optstring found */ 522 doupdate = 0; 523 if (proto != NULL && dataset != NULL) { 524 optstring = sa_proto_legacy_format(proto, group, 1); 525 zfsopts = get_zfs_property(dataset, ZFS_PROP_SHARENFS); 526 527 if (optstring != NULL && zfsopts != NULL) { 528 if (strcmp(optstring, zfsopts) != 0) 529 doupdate++; 530 } 531 532 if (doupdate) { 533 if (optstring != NULL && strlen(optstring) > 0) { 534 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 535 "%s set sharenfs=%s %s", COMMAND, 536 optstring, dataset); 537 } else { 538 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 539 "%s set sharenfs=on %s", COMMAND, 540 dataset); 541 } 542 pfile = popen(command, "r"); 543 if (pfile != NULL) 544 ret = pclose(pfile); 545 switch (ret) { 546 default: 547 case 1: 548 ret = SA_SYSTEM_ERR; 549 break; 550 case 2: 551 ret = SA_SYNTAX_ERR; 552 break; 553 case 0: 554 break; 555 } 556 } 557 if (optstring != NULL) { 558 free(optstring); 559 } 560 if (zfsopts != NULL) 561 free(zfsopts); 562 } 563 if (proto != NULL) 564 sa_free_attr_string(proto); 565 if (dataset != NULL) 566 free(dataset); 567 } 568 free(command); 569 } 570 return (ret); 571 } 572 573 /* 574 * sa_group_is_zfs(group) 575 * 576 * Given the group, determine if the zfs attribute is set. 577 */ 578 579 int 580 sa_group_is_zfs(sa_group_t group) 581 { 582 char *zfs; 583 int ret = 0; 584 585 zfs = sa_get_group_attr(group, "zfs"); 586 if (zfs != NULL) { 587 ret = 1; 588 sa_free_attr_string(zfs); 589 } 590 return (ret); 591 } 592 593 /* 594 * sa_path_is_zfs(path) 595 * 596 * Check to see if the file system path represents is of type "zfs". 597 */ 598 599 int 600 sa_path_is_zfs(char *path) 601 { 602 char *fstype; 603 int ret = 0; 604 605 fstype = sa_fstype(path); 606 if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 607 ret = 1; 608 } 609 if (fstype != NULL) 610 sa_free_fstype(fstype); 611 return (ret); 612 } 613