1*6185db85Sdougm /* 2*6185db85Sdougm * CDDL HEADER START 3*6185db85Sdougm * 4*6185db85Sdougm * The contents of this file are subject to the terms of the 5*6185db85Sdougm * Common Development and Distribution License (the "License"). 6*6185db85Sdougm * You may not use this file except in compliance with the License. 7*6185db85Sdougm * 8*6185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6185db85Sdougm * or http://www.opensolaris.org/os/licensing. 10*6185db85Sdougm * See the License for the specific language governing permissions 11*6185db85Sdougm * and limitations under the License. 12*6185db85Sdougm * 13*6185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 14*6185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 16*6185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 17*6185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 18*6185db85Sdougm * 19*6185db85Sdougm * CDDL HEADER END 20*6185db85Sdougm */ 21*6185db85Sdougm 22*6185db85Sdougm /* 23*6185db85Sdougm * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*6185db85Sdougm * Use is subject to license terms. 25*6185db85Sdougm */ 26*6185db85Sdougm 27*6185db85Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 28*6185db85Sdougm 29*6185db85Sdougm /* 30*6185db85Sdougm * Share control API 31*6185db85Sdougm */ 32*6185db85Sdougm #include <stdio.h> 33*6185db85Sdougm #include <string.h> 34*6185db85Sdougm #include <ctype.h> 35*6185db85Sdougm #include <sys/types.h> 36*6185db85Sdougm #include <sys/stat.h> 37*6185db85Sdougm #include <unistd.h> 38*6185db85Sdougm #include <libxml/parser.h> 39*6185db85Sdougm #include <libxml/tree.h> 40*6185db85Sdougm #include "libshare.h" 41*6185db85Sdougm #include "libshare_impl.h" 42*6185db85Sdougm #include <libscf.h> 43*6185db85Sdougm #include "scfutil.h" 44*6185db85Sdougm #include <ctype.h> 45*6185db85Sdougm #include <libintl.h> 46*6185db85Sdougm 47*6185db85Sdougm #if _NOT_SMF 48*6185db85Sdougm #define CONFIG_FILE "/var/tmp/share.cfg" 49*6185db85Sdougm #define CONFIG_FILE_TMP "/var/tmp/share.cfg.tmp" 50*6185db85Sdougm #endif 51*6185db85Sdougm #define TSTAMP(tm) (uint64_t)(((uint64_t)tm.tv_sec << 32) | \ 52*6185db85Sdougm (tm.tv_nsec & 0xffffffff)) 53*6185db85Sdougm 54*6185db85Sdougm /* 55*6185db85Sdougm * internal data structures 56*6185db85Sdougm */ 57*6185db85Sdougm 58*6185db85Sdougm static xmlNodePtr sa_config_tree; /* the current config */ 59*6185db85Sdougm static xmlDocPtr sa_config_doc = NULL; /* current config document */ 60*6185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 61*6185db85Sdougm 62*6185db85Sdougm /* current SMF/SVC repository handle */ 63*6185db85Sdougm static scfutilhandle_t *scf_handle = NULL; 64*6185db85Sdougm extern void getlegacyconfig(char *, xmlNodePtr *); 65*6185db85Sdougm extern int gettransients(xmlNodePtr *); 66*6185db85Sdougm extern int sa_valid_property(void *, char *, sa_property_t); 67*6185db85Sdougm extern char *sa_fstype(char *); 68*6185db85Sdougm extern int sa_is_share(void *); 69*6185db85Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 70*6185db85Sdougm extern int sa_group_is_zfs(sa_group_t); 71*6185db85Sdougm extern int sa_path_is_zfs(char *); 72*6185db85Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 73*6185db85Sdougm extern void update_legacy_config(void); 74*6185db85Sdougm extern int issubdir(char *, char *); 75*6185db85Sdougm 76*6185db85Sdougm static int sa_initialized = 0; 77*6185db85Sdougm 78*6185db85Sdougm /* helper functions */ 79*6185db85Sdougm 80*6185db85Sdougm char * 81*6185db85Sdougm sa_errorstr(int err) 82*6185db85Sdougm { 83*6185db85Sdougm static char errstr[32]; 84*6185db85Sdougm char *ret = NULL; 85*6185db85Sdougm 86*6185db85Sdougm switch (err) { 87*6185db85Sdougm case SA_OK: 88*6185db85Sdougm ret = gettext("ok"); 89*6185db85Sdougm break; 90*6185db85Sdougm case SA_NO_SUCH_PATH: 91*6185db85Sdougm ret = gettext("path doesn't exist"); 92*6185db85Sdougm break; 93*6185db85Sdougm case SA_NO_MEMORY: 94*6185db85Sdougm ret = gettext("no memory"); 95*6185db85Sdougm break; 96*6185db85Sdougm case SA_DUPLICATE_NAME: 97*6185db85Sdougm ret = gettext("name in use"); 98*6185db85Sdougm break; 99*6185db85Sdougm case SA_BAD_PATH: 100*6185db85Sdougm ret = gettext("bad path"); 101*6185db85Sdougm break; 102*6185db85Sdougm case SA_NO_SUCH_GROUP: 103*6185db85Sdougm ret = gettext("no such group"); 104*6185db85Sdougm break; 105*6185db85Sdougm case SA_CONFIG_ERR: 106*6185db85Sdougm ret = gettext("configuration error"); 107*6185db85Sdougm break; 108*6185db85Sdougm case SA_SYSTEM_ERR: 109*6185db85Sdougm ret = gettext("system error"); 110*6185db85Sdougm break; 111*6185db85Sdougm case SA_SYNTAX_ERR: 112*6185db85Sdougm ret = gettext("syntax error"); 113*6185db85Sdougm break; 114*6185db85Sdougm case SA_NO_PERMISSION: 115*6185db85Sdougm ret = gettext("no permission"); 116*6185db85Sdougm break; 117*6185db85Sdougm case SA_BUSY: 118*6185db85Sdougm ret = gettext("busy"); 119*6185db85Sdougm break; 120*6185db85Sdougm case SA_NO_SUCH_PROP: 121*6185db85Sdougm ret = gettext("no such property"); 122*6185db85Sdougm break; 123*6185db85Sdougm case SA_INVALID_NAME: 124*6185db85Sdougm ret = gettext("invalid name"); 125*6185db85Sdougm break; 126*6185db85Sdougm case SA_INVALID_PROTOCOL: 127*6185db85Sdougm ret = gettext("invalid protocol"); 128*6185db85Sdougm break; 129*6185db85Sdougm case SA_NOT_ALLOWED: 130*6185db85Sdougm ret = gettext("operation not allowed"); 131*6185db85Sdougm break; 132*6185db85Sdougm case SA_BAD_VALUE: 133*6185db85Sdougm ret = gettext("bad property value"); 134*6185db85Sdougm break; 135*6185db85Sdougm case SA_INVALID_SECURITY: 136*6185db85Sdougm ret = gettext("invalid security type"); 137*6185db85Sdougm break; 138*6185db85Sdougm case SA_NO_SUCH_SECURITY: 139*6185db85Sdougm ret = gettext("security type not found"); 140*6185db85Sdougm break; 141*6185db85Sdougm case SA_VALUE_CONFLICT: 142*6185db85Sdougm ret = gettext("property value conflict"); 143*6185db85Sdougm break; 144*6185db85Sdougm case SA_NOT_IMPLEMENTED: 145*6185db85Sdougm ret = gettext("not implemented"); 146*6185db85Sdougm break; 147*6185db85Sdougm case SA_INVALID_PATH: 148*6185db85Sdougm ret = gettext("invalid path"); 149*6185db85Sdougm break; 150*6185db85Sdougm case SA_NOT_SUPPORTED: 151*6185db85Sdougm ret = gettext("operation not supported"); 152*6185db85Sdougm break; 153*6185db85Sdougm case SA_PROP_SHARE_ONLY: 154*6185db85Sdougm ret = gettext("property not valid for group"); 155*6185db85Sdougm break; 156*6185db85Sdougm case SA_NOT_SHARED: 157*6185db85Sdougm ret = gettext("not shared"); 158*6185db85Sdougm break; 159*6185db85Sdougm default: 160*6185db85Sdougm (void) snprintf(errstr, sizeof (errstr), 161*6185db85Sdougm gettext("unknown %d"), err); 162*6185db85Sdougm ret = errstr; 163*6185db85Sdougm } 164*6185db85Sdougm return (ret); 165*6185db85Sdougm } 166*6185db85Sdougm 167*6185db85Sdougm /* 168*6185db85Sdougm * get_legacy_timestamp(root, path) 169*6185db85Sdougm * gets the timestamp of the last time sharemgr updated the legacy 170*6185db85Sdougm * files. This is used to determine if someone has modified them by 171*6185db85Sdougm * hand. 172*6185db85Sdougm */ 173*6185db85Sdougm static uint64_t 174*6185db85Sdougm get_legacy_timestamp(xmlNodePtr root, char *path) 175*6185db85Sdougm { 176*6185db85Sdougm uint64_t tval = 0; 177*6185db85Sdougm xmlNodePtr node; 178*6185db85Sdougm xmlChar *lpath = NULL; 179*6185db85Sdougm xmlChar *timestamp = NULL; 180*6185db85Sdougm 181*6185db85Sdougm for (node = root->xmlChildrenNode; node != NULL; 182*6185db85Sdougm node = node->next) { 183*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 184*6185db85Sdougm /* a possible legacy node for this path */ 185*6185db85Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 186*6185db85Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 187*6185db85Sdougm /* now have the node, extract the data */ 188*6185db85Sdougm timestamp = xmlGetProp(node, (xmlChar *)"timestamp"); 189*6185db85Sdougm if (timestamp != NULL) { 190*6185db85Sdougm tval = strtoull((char *)timestamp, NULL, 0); 191*6185db85Sdougm break; 192*6185db85Sdougm } 193*6185db85Sdougm } 194*6185db85Sdougm if (lpath != NULL) { 195*6185db85Sdougm xmlFree(lpath); 196*6185db85Sdougm lpath = NULL; 197*6185db85Sdougm } 198*6185db85Sdougm } 199*6185db85Sdougm } 200*6185db85Sdougm if (lpath != NULL) 201*6185db85Sdougm xmlFree(lpath); 202*6185db85Sdougm if (timestamp != NULL) 203*6185db85Sdougm xmlFree(timestamp); 204*6185db85Sdougm return (tval); 205*6185db85Sdougm } 206*6185db85Sdougm 207*6185db85Sdougm /* 208*6185db85Sdougm * set_legacy_timestamp(root, path, timevalue) 209*6185db85Sdougm * 210*6185db85Sdougm * add the current timestamp value to the configuration for use in 211*6185db85Sdougm * determining when to update the legacy files. For SMF, this 212*6185db85Sdougm * property is kept in default/operation/legacy_timestamp 213*6185db85Sdougm */ 214*6185db85Sdougm 215*6185db85Sdougm static void 216*6185db85Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 217*6185db85Sdougm { 218*6185db85Sdougm xmlNodePtr node; 219*6185db85Sdougm xmlChar *lpath = NULL; 220*6185db85Sdougm 221*6185db85Sdougm for (node = root->xmlChildrenNode; node != NULL; 222*6185db85Sdougm node = node->next) { 223*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 224*6185db85Sdougm /* a possible legacy node for this path */ 225*6185db85Sdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 226*6185db85Sdougm if (lpath != NULL && xmlStrcmp(lpath, (xmlChar *)path) == 0) { 227*6185db85Sdougm xmlFree(lpath); 228*6185db85Sdougm break; 229*6185db85Sdougm } 230*6185db85Sdougm if (lpath != NULL) 231*6185db85Sdougm xmlFree(lpath); 232*6185db85Sdougm } 233*6185db85Sdougm } 234*6185db85Sdougm if (node == NULL) { 235*6185db85Sdougm /* need to create the first legacy timestamp node */ 236*6185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 237*6185db85Sdougm } 238*6185db85Sdougm if (node != NULL) { 239*6185db85Sdougm char tstring[32]; 240*6185db85Sdougm int ret; 241*6185db85Sdougm 242*6185db85Sdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 243*6185db85Sdougm xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring); 244*6185db85Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 245*6185db85Sdougm /* now commit to SMF */ 246*6185db85Sdougm ret = sa_get_instance(scf_handle, "default"); 247*6185db85Sdougm if (ret == SA_OK) { 248*6185db85Sdougm ret = sa_start_transaction(scf_handle, "operation"); 249*6185db85Sdougm if (ret == SA_OK) { 250*6185db85Sdougm ret = sa_set_property(scf_handle, "legacy-timestamp", 251*6185db85Sdougm tstring); 252*6185db85Sdougm if (ret == SA_OK) { 253*6185db85Sdougm (void) sa_end_transaction(scf_handle); 254*6185db85Sdougm } else { 255*6185db85Sdougm sa_abort_transaction(scf_handle); 256*6185db85Sdougm } 257*6185db85Sdougm } 258*6185db85Sdougm } 259*6185db85Sdougm } 260*6185db85Sdougm } 261*6185db85Sdougm 262*6185db85Sdougm /* 263*6185db85Sdougm * is_shared(share) 264*6185db85Sdougm * 265*6185db85Sdougm * determine if the specified share is currently shared or not. 266*6185db85Sdougm */ 267*6185db85Sdougm static int 268*6185db85Sdougm is_shared(sa_share_t share) 269*6185db85Sdougm { 270*6185db85Sdougm char *shared; 271*6185db85Sdougm int result = 0; /* assume not */ 272*6185db85Sdougm 273*6185db85Sdougm shared = sa_get_share_attr(share, "shared"); 274*6185db85Sdougm if (shared != NULL) { 275*6185db85Sdougm if (strcmp(shared, "true") == 0) 276*6185db85Sdougm result = 1; 277*6185db85Sdougm sa_free_attr_string(shared); 278*6185db85Sdougm } 279*6185db85Sdougm return (result); 280*6185db85Sdougm } 281*6185db85Sdougm 282*6185db85Sdougm /* 283*6185db85Sdougm * checksubdir determines if the specified path is a subdirectory of 284*6185db85Sdougm * another share. It calls issubdir() from the old share 285*6185db85Sdougm * implementation to do the complicated work. 286*6185db85Sdougm */ 287*6185db85Sdougm static int 288*6185db85Sdougm checksubdir(char *newpath) 289*6185db85Sdougm { 290*6185db85Sdougm sa_group_t group; 291*6185db85Sdougm sa_share_t share; 292*6185db85Sdougm int issub; 293*6185db85Sdougm char *path = NULL; 294*6185db85Sdougm 295*6185db85Sdougm for (issub = 0, group = sa_get_group(NULL); 296*6185db85Sdougm group != NULL && !issub; 297*6185db85Sdougm group = sa_get_next_group(group)) { 298*6185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 299*6185db85Sdougm share = sa_get_next_share(share)) { 300*6185db85Sdougm /* 301*6185db85Sdougm * The original behavior of share never checked 302*6185db85Sdougm * against the permanent configuration 303*6185db85Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 304*6185db85Sdougm * it depends on this older behavior even though it 305*6185db85Sdougm * could be considered incorrect. We may tighten this 306*6185db85Sdougm * up in the future. 307*6185db85Sdougm */ 308*6185db85Sdougm if (!is_shared(share)) 309*6185db85Sdougm continue; 310*6185db85Sdougm 311*6185db85Sdougm path = sa_get_share_attr(share, "path"); 312*6185db85Sdougm if (newpath != NULL && 313*6185db85Sdougm (strcmp(path, newpath) == 0 || issubdir(newpath, path) || 314*6185db85Sdougm issubdir(path, newpath))) { 315*6185db85Sdougm sa_free_attr_string(path); 316*6185db85Sdougm path = NULL; 317*6185db85Sdougm issub = SA_INVALID_PATH; 318*6185db85Sdougm break; 319*6185db85Sdougm } 320*6185db85Sdougm sa_free_attr_string(path); 321*6185db85Sdougm path = NULL; 322*6185db85Sdougm } 323*6185db85Sdougm } 324*6185db85Sdougm if (path != NULL) 325*6185db85Sdougm sa_free_attr_string(path); 326*6185db85Sdougm return (issub); 327*6185db85Sdougm } 328*6185db85Sdougm 329*6185db85Sdougm /* 330*6185db85Sdougm * validpath(path) 331*6185db85Sdougm * determine if the provided path is valid for a share. It shouldn't 332*6185db85Sdougm * be a sub-dir of an already shared path or the parent directory of a 333*6185db85Sdougm * share path. 334*6185db85Sdougm */ 335*6185db85Sdougm static int 336*6185db85Sdougm validpath(char *path) 337*6185db85Sdougm { 338*6185db85Sdougm int error = SA_OK; 339*6185db85Sdougm struct stat st; 340*6185db85Sdougm sa_share_t share; 341*6185db85Sdougm char *fstype; 342*6185db85Sdougm 343*6185db85Sdougm if (*path != '/') { 344*6185db85Sdougm return (SA_BAD_PATH); 345*6185db85Sdougm } 346*6185db85Sdougm if (stat(path, &st) < 0) { 347*6185db85Sdougm error = SA_NO_SUCH_PATH; 348*6185db85Sdougm } else { 349*6185db85Sdougm share = sa_find_share(path); 350*6185db85Sdougm if (share != NULL) { 351*6185db85Sdougm error = SA_DUPLICATE_NAME; 352*6185db85Sdougm } 353*6185db85Sdougm if (error == SA_OK) { 354*6185db85Sdougm /* 355*6185db85Sdougm * check for special case with file system that might 356*6185db85Sdougm * have restrictions. For now, ZFS is the only case 357*6185db85Sdougm * since it has its own idea of how to configure 358*6185db85Sdougm * shares. We do this before subdir checking since 359*6185db85Sdougm * things like ZFS will do that for us. This should 360*6185db85Sdougm * also be done via plugin interface. 361*6185db85Sdougm */ 362*6185db85Sdougm fstype = sa_fstype(path); 363*6185db85Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 364*6185db85Sdougm if (sa_zfs_is_shared(path)) 365*6185db85Sdougm error = SA_DUPLICATE_NAME; 366*6185db85Sdougm } 367*6185db85Sdougm if (fstype != NULL) 368*6185db85Sdougm sa_free_fstype(fstype); 369*6185db85Sdougm } 370*6185db85Sdougm if (error == SA_OK) { 371*6185db85Sdougm error = checksubdir(path); 372*6185db85Sdougm } 373*6185db85Sdougm } 374*6185db85Sdougm return (error); 375*6185db85Sdougm } 376*6185db85Sdougm 377*6185db85Sdougm /* 378*6185db85Sdougm * check to see if group/share is persistent. 379*6185db85Sdougm */ 380*6185db85Sdougm static int 381*6185db85Sdougm is_persistent(sa_group_t group) 382*6185db85Sdougm { 383*6185db85Sdougm char *type; 384*6185db85Sdougm int persist = 1; 385*6185db85Sdougm 386*6185db85Sdougm type = sa_get_group_attr(group, "type"); 387*6185db85Sdougm if (type != NULL && strcmp(type, "transient") == 0) 388*6185db85Sdougm persist = 0; 389*6185db85Sdougm if (type != NULL) 390*6185db85Sdougm sa_free_attr_string(type); 391*6185db85Sdougm return (persist); 392*6185db85Sdougm } 393*6185db85Sdougm 394*6185db85Sdougm /* 395*6185db85Sdougm * sa_valid_group_name(name) 396*6185db85Sdougm * 397*6185db85Sdougm * check that the "name" contains only valid characters and otherwise 398*6185db85Sdougm * fits the required naming conventions. Valid names must start with 399*6185db85Sdougm * an alphabetic and the remainder may consist of only alphanumeric 400*6185db85Sdougm * plus the '-' and '_' characters. This name limitation comes from 401*6185db85Sdougm * inherent limitations in SMF. 402*6185db85Sdougm */ 403*6185db85Sdougm 404*6185db85Sdougm int 405*6185db85Sdougm sa_valid_group_name(char *name) 406*6185db85Sdougm { 407*6185db85Sdougm int ret = 1; 408*6185db85Sdougm ssize_t len; 409*6185db85Sdougm 410*6185db85Sdougm if (name != NULL && isalpha(*name)) { 411*6185db85Sdougm char c; 412*6185db85Sdougm len = strlen(name); 413*6185db85Sdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 414*6185db85Sdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 415*6185db85Sdougm if (!isalnum(c) && c != '-' && c != '_') 416*6185db85Sdougm ret = 0; 417*6185db85Sdougm } 418*6185db85Sdougm } else { 419*6185db85Sdougm ret = 0; 420*6185db85Sdougm } 421*6185db85Sdougm } else { 422*6185db85Sdougm ret = 0; 423*6185db85Sdougm } 424*6185db85Sdougm return (ret); 425*6185db85Sdougm } 426*6185db85Sdougm 427*6185db85Sdougm 428*6185db85Sdougm /* 429*6185db85Sdougm * is_zfs_group(group) 430*6185db85Sdougm * Determine if the specified group is a ZFS sharenfs group 431*6185db85Sdougm */ 432*6185db85Sdougm static int 433*6185db85Sdougm is_zfs_group(sa_group_t group) 434*6185db85Sdougm { 435*6185db85Sdougm int ret = 0; 436*6185db85Sdougm xmlNodePtr parent; 437*6185db85Sdougm xmlChar *zfs; 438*6185db85Sdougm 439*6185db85Sdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) { 440*6185db85Sdougm parent = (xmlNodePtr)sa_get_parent_group(group); 441*6185db85Sdougm } else { 442*6185db85Sdougm parent = (xmlNodePtr)group; 443*6185db85Sdougm } 444*6185db85Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 445*6185db85Sdougm if (zfs != NULL) { 446*6185db85Sdougm xmlFree(zfs); 447*6185db85Sdougm ret = 1; 448*6185db85Sdougm } 449*6185db85Sdougm return (ret); 450*6185db85Sdougm } 451*6185db85Sdougm 452*6185db85Sdougm /* 453*6185db85Sdougm * sa_optionset_name(optionset, oname, len, id) 454*6185db85Sdougm * return the SMF name for the optionset. If id is not NULL, it 455*6185db85Sdougm * will have the GUID value for a share and should be used 456*6185db85Sdougm * instead of the keyword "optionset" which is used for 457*6185db85Sdougm * groups. If the optionset doesn't have a protocol type 458*6185db85Sdougm * associated with it, "default" is used. This shouldn't happen 459*6185db85Sdougm * at this point but may be desirable in the future if there are 460*6185db85Sdougm * protocol independent properties added. The name is returned in 461*6185db85Sdougm * oname. 462*6185db85Sdougm */ 463*6185db85Sdougm 464*6185db85Sdougm static int 465*6185db85Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 466*6185db85Sdougm { 467*6185db85Sdougm char *proto; 468*6185db85Sdougm 469*6185db85Sdougm if (id == NULL) 470*6185db85Sdougm id = "optionset"; 471*6185db85Sdougm 472*6185db85Sdougm proto = sa_get_optionset_attr(optionset, "type"); 473*6185db85Sdougm len = snprintf(oname, len, "%s_%s", id, proto ? proto : "default"); 474*6185db85Sdougm 475*6185db85Sdougm if (proto != NULL) 476*6185db85Sdougm sa_free_attr_string(proto); 477*6185db85Sdougm return (len); 478*6185db85Sdougm } 479*6185db85Sdougm 480*6185db85Sdougm /* 481*6185db85Sdougm * sa_security_name(optionset, oname, len, id) 482*6185db85Sdougm * 483*6185db85Sdougm * return the SMF name for the security. If id is not NULL, it will 484*6185db85Sdougm * have the GUID value for a share and should be used instead of the 485*6185db85Sdougm * keyword "optionset" which is used for groups. If the optionset 486*6185db85Sdougm * doesn't have a protocol type associated with it, "default" is 487*6185db85Sdougm * used. This shouldn't happen at this point but may be desirable in 488*6185db85Sdougm * the future if there are protocol independent properties added. The 489*6185db85Sdougm * name is returned in oname. The security type is also encoded into 490*6185db85Sdougm * the name. In the future, this wil *be handled a bit differently. 491*6185db85Sdougm */ 492*6185db85Sdougm 493*6185db85Sdougm static int 494*6185db85Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 495*6185db85Sdougm { 496*6185db85Sdougm char *proto; 497*6185db85Sdougm char *sectype; 498*6185db85Sdougm 499*6185db85Sdougm if (id == NULL) 500*6185db85Sdougm id = "optionset"; 501*6185db85Sdougm 502*6185db85Sdougm proto = sa_get_security_attr(security, "type"); 503*6185db85Sdougm sectype = sa_get_security_attr(security, "sectype"); 504*6185db85Sdougm len = snprintf(oname, len, "%s_%s_%s", id, 505*6185db85Sdougm proto ? proto : "default", 506*6185db85Sdougm sectype ? sectype : "default"); 507*6185db85Sdougm if (proto != NULL) 508*6185db85Sdougm sa_free_attr_string(proto); 509*6185db85Sdougm if (sectype != NULL) 510*6185db85Sdougm sa_free_attr_string(sectype); 511*6185db85Sdougm return (len); 512*6185db85Sdougm } 513*6185db85Sdougm 514*6185db85Sdougm /* 515*6185db85Sdougm * sa_init() 516*6185db85Sdougm * Initialize the API 517*6185db85Sdougm * find all the shared objects 518*6185db85Sdougm * init the tables with all objects 519*6185db85Sdougm * read in the current configuration 520*6185db85Sdougm */ 521*6185db85Sdougm 522*6185db85Sdougm void 523*6185db85Sdougm sa_init(int init_service) 524*6185db85Sdougm { 525*6185db85Sdougm struct stat st; 526*6185db85Sdougm int legacy = 0; 527*6185db85Sdougm uint64_t tval = 0; 528*6185db85Sdougm 529*6185db85Sdougm if (!sa_initialized) { 530*6185db85Sdougm /* get protocol specific structures */ 531*6185db85Sdougm (void) proto_plugin_init(); 532*6185db85Sdougm if (init_service & SA_INIT_SHARE_API) { 533*6185db85Sdougm /* 534*6185db85Sdougm * since we want to use SMF, initialize an svc handle 535*6185db85Sdougm * and find out what is there. 536*6185db85Sdougm */ 537*6185db85Sdougm scf_handle = sa_scf_init(); 538*6185db85Sdougm if (scf_handle != NULL) { 539*6185db85Sdougm (void) sa_get_config(scf_handle, &sa_config_tree, 540*6185db85Sdougm &sa_config_doc); 541*6185db85Sdougm tval = get_legacy_timestamp(sa_config_tree, 542*6185db85Sdougm SA_LEGACY_DFSTAB); 543*6185db85Sdougm if (tval == 0) { 544*6185db85Sdougm /* first time so make sure default is setup */ 545*6185db85Sdougm sa_group_t defgrp; 546*6185db85Sdougm sa_optionset_t opt; 547*6185db85Sdougm defgrp = sa_get_group("default"); 548*6185db85Sdougm if (defgrp != NULL) { 549*6185db85Sdougm opt = sa_get_optionset(defgrp, NULL); 550*6185db85Sdougm if (opt == NULL) 551*6185db85Sdougm /* NFS is the default for default */ 552*6185db85Sdougm opt = sa_create_optionset(defgrp, "nfs"); 553*6185db85Sdougm } 554*6185db85Sdougm } 555*6185db85Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0 && 556*6185db85Sdougm tval != TSTAMP(st.st_ctim)) { 557*6185db85Sdougm getlegacyconfig(SA_LEGACY_DFSTAB, &sa_config_tree); 558*6185db85Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 559*6185db85Sdougm set_legacy_timestamp(sa_config_tree, 560*6185db85Sdougm SA_LEGACY_DFSTAB, 561*6185db85Sdougm TSTAMP(st.st_ctim)); 562*6185db85Sdougm } 563*6185db85Sdougm legacy |= sa_get_zfs_shares("zfs"); 564*6185db85Sdougm legacy |= gettransients(&sa_config_tree); 565*6185db85Sdougm } 566*6185db85Sdougm } 567*6185db85Sdougm } 568*6185db85Sdougm } 569*6185db85Sdougm 570*6185db85Sdougm /* 571*6185db85Sdougm * sa_fini() 572*6185db85Sdougm * Uninitialize the API structures including the configuration 573*6185db85Sdougm * data structures 574*6185db85Sdougm */ 575*6185db85Sdougm 576*6185db85Sdougm void 577*6185db85Sdougm sa_fini() 578*6185db85Sdougm { 579*6185db85Sdougm if (sa_initialized) { 580*6185db85Sdougm /* free the config trees */ 581*6185db85Sdougm sa_initialized = 0; 582*6185db85Sdougm if (sa_config_doc != NULL) 583*6185db85Sdougm xmlFreeDoc(sa_config_doc); 584*6185db85Sdougm sa_config_tree = NULL; 585*6185db85Sdougm sa_config_doc = NULL; 586*6185db85Sdougm sa_scf_fini(scf_handle); 587*6185db85Sdougm (void) proto_plugin_init(); 588*6185db85Sdougm } 589*6185db85Sdougm } 590*6185db85Sdougm 591*6185db85Sdougm /* 592*6185db85Sdougm * sa_get_protocols(char **protocol) 593*6185db85Sdougm * Get array of protocols that are supported 594*6185db85Sdougm * Returns pointer to an allocated and NULL terminated 595*6185db85Sdougm * array of strings. Caller must free. 596*6185db85Sdougm * This really should be determined dynamically. 597*6185db85Sdougm * If there aren't any defined, return -1. 598*6185db85Sdougm * Use free() to return memory. 599*6185db85Sdougm */ 600*6185db85Sdougm 601*6185db85Sdougm int 602*6185db85Sdougm sa_get_protocols(char ***protocols) 603*6185db85Sdougm { 604*6185db85Sdougm int numproto = -1; 605*6185db85Sdougm 606*6185db85Sdougm if (protocols != NULL) { 607*6185db85Sdougm struct sa_proto_plugin *plug; 608*6185db85Sdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 609*6185db85Sdougm plug = plug->plugin_next) { 610*6185db85Sdougm numproto++; 611*6185db85Sdougm } 612*6185db85Sdougm 613*6185db85Sdougm *protocols = calloc(numproto + 1, sizeof (char *)); 614*6185db85Sdougm if (*protocols != NULL) { 615*6185db85Sdougm int ret = 0; 616*6185db85Sdougm for (plug = sap_proto_list; plug != NULL; 617*6185db85Sdougm plug = plug->plugin_next) { 618*6185db85Sdougm /* faking for now */ 619*6185db85Sdougm (*protocols)[ret++] = plug->plugin_ops->sa_protocol; 620*6185db85Sdougm } 621*6185db85Sdougm } else { 622*6185db85Sdougm numproto = -1; 623*6185db85Sdougm } 624*6185db85Sdougm } 625*6185db85Sdougm return (numproto); 626*6185db85Sdougm } 627*6185db85Sdougm 628*6185db85Sdougm /* 629*6185db85Sdougm * find_group_by_name(node, group) 630*6185db85Sdougm * 631*6185db85Sdougm * search the XML document subtree specified by node to find the group 632*6185db85Sdougm * specified by group. Searching subtree allows subgroups to be 633*6185db85Sdougm * searched for. 634*6185db85Sdougm */ 635*6185db85Sdougm 636*6185db85Sdougm static xmlNodePtr 637*6185db85Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 638*6185db85Sdougm { 639*6185db85Sdougm xmlChar *name = NULL; 640*6185db85Sdougm 641*6185db85Sdougm for (node = node->xmlChildrenNode; node != NULL; 642*6185db85Sdougm node = node->next) { 643*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 644*6185db85Sdougm /* if no groupname, return the first found */ 645*6185db85Sdougm if (group == NULL) 646*6185db85Sdougm break; 647*6185db85Sdougm name = xmlGetProp(node, (xmlChar *)"name"); 648*6185db85Sdougm if (name != NULL && 649*6185db85Sdougm xmlStrcmp(name, group) == 0) { 650*6185db85Sdougm break; 651*6185db85Sdougm } 652*6185db85Sdougm if (name != NULL) { 653*6185db85Sdougm xmlFree(name); 654*6185db85Sdougm name = NULL; 655*6185db85Sdougm } 656*6185db85Sdougm } 657*6185db85Sdougm } 658*6185db85Sdougm if (name != NULL) 659*6185db85Sdougm xmlFree(name); 660*6185db85Sdougm return (node); 661*6185db85Sdougm } 662*6185db85Sdougm 663*6185db85Sdougm /* 664*6185db85Sdougm * sa_get_group(groupname) 665*6185db85Sdougm * Return the "group" specified. If groupname is NULL, 666*6185db85Sdougm * return the first group of the list of groups. 667*6185db85Sdougm */ 668*6185db85Sdougm sa_group_t 669*6185db85Sdougm sa_get_group(char *groupname) 670*6185db85Sdougm { 671*6185db85Sdougm xmlNodePtr node = NULL; 672*6185db85Sdougm char *subgroup = NULL; 673*6185db85Sdougm char *group = NULL; 674*6185db85Sdougm 675*6185db85Sdougm if (sa_config_tree != NULL) { 676*6185db85Sdougm if (groupname != NULL) { 677*6185db85Sdougm group = strdup(groupname); 678*6185db85Sdougm subgroup = strchr(group, '/'); 679*6185db85Sdougm if (subgroup != NULL) 680*6185db85Sdougm *subgroup++ = '\0'; 681*6185db85Sdougm } 682*6185db85Sdougm node = find_group_by_name(sa_config_tree, (xmlChar *)group); 683*6185db85Sdougm /* if a subgroup, find it before returning */ 684*6185db85Sdougm if (subgroup != NULL && node != NULL) { 685*6185db85Sdougm node = find_group_by_name(node, (xmlChar *)subgroup); 686*6185db85Sdougm } 687*6185db85Sdougm } 688*6185db85Sdougm if (node != NULL && (char *)group != NULL) 689*6185db85Sdougm (void) sa_get_instance(scf_handle, (char *)group); 690*6185db85Sdougm if (group != NULL) 691*6185db85Sdougm free(group); 692*6185db85Sdougm return ((sa_group_t)(node)); 693*6185db85Sdougm } 694*6185db85Sdougm 695*6185db85Sdougm /* 696*6185db85Sdougm * sa_get_next_group(group) 697*6185db85Sdougm * Return the "next" group after the specified group from 698*6185db85Sdougm * the internal group list. NULL if there are no more. 699*6185db85Sdougm */ 700*6185db85Sdougm sa_group_t 701*6185db85Sdougm sa_get_next_group(sa_group_t group) 702*6185db85Sdougm { 703*6185db85Sdougm xmlNodePtr ngroup = NULL; 704*6185db85Sdougm if (group != NULL) { 705*6185db85Sdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 706*6185db85Sdougm ngroup = ngroup->next) { 707*6185db85Sdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 708*6185db85Sdougm break; 709*6185db85Sdougm } 710*6185db85Sdougm } 711*6185db85Sdougm return ((sa_group_t)ngroup); 712*6185db85Sdougm } 713*6185db85Sdougm 714*6185db85Sdougm /* 715*6185db85Sdougm * sa_get_share(group, sharepath) 716*6185db85Sdougm * Return the share object for the share specified. The share 717*6185db85Sdougm * must be in the specified group. Return NULL if not found. 718*6185db85Sdougm */ 719*6185db85Sdougm sa_share_t 720*6185db85Sdougm sa_get_share(sa_group_t group, char *sharepath) 721*6185db85Sdougm { 722*6185db85Sdougm xmlNodePtr node = NULL; 723*6185db85Sdougm xmlChar *path; 724*6185db85Sdougm 725*6185db85Sdougm /* 726*6185db85Sdougm * For future scalability, this should end up building a cache 727*6185db85Sdougm * since it will get called regularly by the mountd and info 728*6185db85Sdougm * services. 729*6185db85Sdougm */ 730*6185db85Sdougm if (group != NULL) { 731*6185db85Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 732*6185db85Sdougm node = node->next) { 733*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 734*6185db85Sdougm if (sharepath == NULL) { 735*6185db85Sdougm break; 736*6185db85Sdougm } else { 737*6185db85Sdougm /* is it the correct share? */ 738*6185db85Sdougm path = xmlGetProp(node, (xmlChar *)"path"); 739*6185db85Sdougm if (path != NULL && 740*6185db85Sdougm xmlStrcmp(path, (xmlChar *)sharepath) == 0) { 741*6185db85Sdougm xmlFree(path); 742*6185db85Sdougm break; 743*6185db85Sdougm } 744*6185db85Sdougm xmlFree(path); 745*6185db85Sdougm } 746*6185db85Sdougm } 747*6185db85Sdougm } 748*6185db85Sdougm } 749*6185db85Sdougm return ((sa_share_t)node); 750*6185db85Sdougm } 751*6185db85Sdougm 752*6185db85Sdougm /* 753*6185db85Sdougm * sa_get_next_share(share) 754*6185db85Sdougm * Return the next share following the specified share 755*6185db85Sdougm * from the internal list of shares. Returns NULL if there 756*6185db85Sdougm * are no more shares. The list is relative to the same 757*6185db85Sdougm * group. 758*6185db85Sdougm */ 759*6185db85Sdougm sa_share_t 760*6185db85Sdougm sa_get_next_share(sa_share_t share) 761*6185db85Sdougm { 762*6185db85Sdougm xmlNodePtr node = NULL; 763*6185db85Sdougm 764*6185db85Sdougm if (share != NULL) { 765*6185db85Sdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 766*6185db85Sdougm node = node->next) { 767*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 768*6185db85Sdougm break; 769*6185db85Sdougm } 770*6185db85Sdougm } 771*6185db85Sdougm } 772*6185db85Sdougm return ((sa_share_t)node); 773*6185db85Sdougm } 774*6185db85Sdougm 775*6185db85Sdougm /* 776*6185db85Sdougm * _sa_get_child_node(node, type) 777*6185db85Sdougm * 778*6185db85Sdougm * find the child node of the specified node that has "type". This is 779*6185db85Sdougm * used to implement several internal functions. 780*6185db85Sdougm */ 781*6185db85Sdougm 782*6185db85Sdougm static xmlNodePtr 783*6185db85Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 784*6185db85Sdougm { 785*6185db85Sdougm xmlNodePtr child; 786*6185db85Sdougm for (child = node->xmlChildrenNode; child != NULL; 787*6185db85Sdougm child = child->next) 788*6185db85Sdougm if (xmlStrcmp(child->name, type) == 0) 789*6185db85Sdougm return (child); 790*6185db85Sdougm return ((xmlNodePtr)NULL); 791*6185db85Sdougm } 792*6185db85Sdougm 793*6185db85Sdougm /* 794*6185db85Sdougm * find_share(group, path) 795*6185db85Sdougm * 796*6185db85Sdougm * Search all the shares in the specified group for one that has the 797*6185db85Sdougm * specified path. 798*6185db85Sdougm */ 799*6185db85Sdougm 800*6185db85Sdougm static sa_share_t 801*6185db85Sdougm find_share(sa_group_t group, char *sharepath) 802*6185db85Sdougm { 803*6185db85Sdougm sa_share_t share; 804*6185db85Sdougm char *path; 805*6185db85Sdougm 806*6185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 807*6185db85Sdougm share = sa_get_next_share(share)) { 808*6185db85Sdougm path = sa_get_share_attr(share, "path"); 809*6185db85Sdougm if (path != NULL && strcmp(path, sharepath) == 0) { 810*6185db85Sdougm sa_free_attr_string(path); 811*6185db85Sdougm break; 812*6185db85Sdougm } 813*6185db85Sdougm if (path != NULL) 814*6185db85Sdougm sa_free_attr_string(path); 815*6185db85Sdougm } 816*6185db85Sdougm return (share); 817*6185db85Sdougm } 818*6185db85Sdougm 819*6185db85Sdougm /* 820*6185db85Sdougm * sa_get_sub_group(group) 821*6185db85Sdougm * 822*6185db85Sdougm * Get the first sub-group of group. The sa_get_next_group() function 823*6185db85Sdougm * can be used to get the rest. This is currently only used for ZFS 824*6185db85Sdougm * sub-groups but could be used to implement a more general mechanism. 825*6185db85Sdougm */ 826*6185db85Sdougm 827*6185db85Sdougm sa_group_t 828*6185db85Sdougm sa_get_sub_group(sa_group_t group) 829*6185db85Sdougm { 830*6185db85Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 831*6185db85Sdougm (xmlChar *)"group")); 832*6185db85Sdougm } 833*6185db85Sdougm 834*6185db85Sdougm /* 835*6185db85Sdougm * sa_find_share(sharepath) 836*6185db85Sdougm * Finds a share regardless of group. In the future, this 837*6185db85Sdougm * function should utilize a cache and hash table of some kind. 838*6185db85Sdougm * The current assumption is that a path will only be shared 839*6185db85Sdougm * once. In the future, this may change as implementation of 840*6185db85Sdougm * resource names comes into being. 841*6185db85Sdougm */ 842*6185db85Sdougm sa_share_t 843*6185db85Sdougm sa_find_share(char *sharepath) 844*6185db85Sdougm { 845*6185db85Sdougm sa_group_t group; 846*6185db85Sdougm sa_group_t zgroup; 847*6185db85Sdougm sa_share_t share = NULL; 848*6185db85Sdougm int done = 0; 849*6185db85Sdougm 850*6185db85Sdougm for (group = sa_get_group(NULL); group != NULL && !done; 851*6185db85Sdougm group = sa_get_next_group(group)) { 852*6185db85Sdougm if (is_zfs_group(group)) { 853*6185db85Sdougm for (zgroup = (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 854*6185db85Sdougm (xmlChar *)"group"); 855*6185db85Sdougm zgroup != NULL; zgroup = sa_get_next_group(zgroup)) { 856*6185db85Sdougm share = find_share(zgroup, sharepath); 857*6185db85Sdougm if (share != NULL) 858*6185db85Sdougm break; 859*6185db85Sdougm } 860*6185db85Sdougm } else { 861*6185db85Sdougm share = find_share(group, sharepath); 862*6185db85Sdougm } 863*6185db85Sdougm if (share != NULL) 864*6185db85Sdougm break; 865*6185db85Sdougm } 866*6185db85Sdougm return (share); 867*6185db85Sdougm } 868*6185db85Sdougm 869*6185db85Sdougm /* 870*6185db85Sdougm * sa_check_path(group, path) 871*6185db85Sdougm * 872*6185db85Sdougm * check that path is a valid path relative to the group. Currently, 873*6185db85Sdougm * we are ignoring the group and checking only the NFS rules. Later, 874*6185db85Sdougm * we may want to use the group to then check against the protocols 875*6185db85Sdougm * enabled on the group. 876*6185db85Sdougm */ 877*6185db85Sdougm 878*6185db85Sdougm int 879*6185db85Sdougm sa_check_path(sa_group_t group, char *path) 880*6185db85Sdougm { 881*6185db85Sdougm #ifdef lint 882*6185db85Sdougm group = group; 883*6185db85Sdougm #endif 884*6185db85Sdougm return (validpath(path)); 885*6185db85Sdougm } 886*6185db85Sdougm 887*6185db85Sdougm /* 888*6185db85Sdougm * _sa_add_share(group, sharepath, persist, *error) 889*6185db85Sdougm * 890*6185db85Sdougm * common code for all types of add_share. sa_add_share() is the 891*6185db85Sdougm * public API, we also need to be able to do this when parsing legacy 892*6185db85Sdougm * files and construction of the internal configuration while 893*6185db85Sdougm * extracting config info from SMF. 894*6185db85Sdougm */ 895*6185db85Sdougm 896*6185db85Sdougm sa_share_t 897*6185db85Sdougm _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 898*6185db85Sdougm { 899*6185db85Sdougm xmlNodePtr node = NULL; 900*6185db85Sdougm int err; 901*6185db85Sdougm 902*6185db85Sdougm err = SA_OK; /* assume success */ 903*6185db85Sdougm 904*6185db85Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 905*6185db85Sdougm (xmlChar *)"share", NULL); 906*6185db85Sdougm if (node != NULL) { 907*6185db85Sdougm xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 908*6185db85Sdougm xmlSetProp(node, (xmlChar *)"type", persist ? 909*6185db85Sdougm (xmlChar *)"persist" : (xmlChar *)"transient"); 910*6185db85Sdougm if (persist != SA_SHARE_TRANSIENT) { 911*6185db85Sdougm /* 912*6185db85Sdougm * persistent shares come in two flavors: SMF and 913*6185db85Sdougm * ZFS. Sort this one out based on target group and 914*6185db85Sdougm * path type. Currently, only NFS is supported in the 915*6185db85Sdougm * ZFS group and it is always on. 916*6185db85Sdougm */ 917*6185db85Sdougm if (sa_group_is_zfs(group) && sa_path_is_zfs(sharepath)) { 918*6185db85Sdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 919*6185db85Sdougm } else { 920*6185db85Sdougm err = sa_commit_share(scf_handle, group, 921*6185db85Sdougm (sa_share_t)node); 922*6185db85Sdougm } 923*6185db85Sdougm } 924*6185db85Sdougm if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) { 925*6185db85Sdougm /* called by the dfstab parser so could be a show */ 926*6185db85Sdougm err = SA_OK; 927*6185db85Sdougm } 928*6185db85Sdougm if (err != SA_OK) { 929*6185db85Sdougm /* 930*6185db85Sdougm * we couldn't commit to the repository so undo 931*6185db85Sdougm * our internal state to reflect reality. 932*6185db85Sdougm */ 933*6185db85Sdougm xmlUnlinkNode(node); 934*6185db85Sdougm xmlFreeNode(node); 935*6185db85Sdougm node = NULL; 936*6185db85Sdougm } 937*6185db85Sdougm } else { 938*6185db85Sdougm err = SA_NO_MEMORY; 939*6185db85Sdougm } 940*6185db85Sdougm if (error != NULL) 941*6185db85Sdougm *error = err; 942*6185db85Sdougm return (node); 943*6185db85Sdougm } 944*6185db85Sdougm 945*6185db85Sdougm /* 946*6185db85Sdougm * sa_add_share(group, sharepath, persist, *error) 947*6185db85Sdougm * 948*6185db85Sdougm * Add a new share object to the specified group. The share will 949*6185db85Sdougm * have the specified sharepath and will only be constructed if 950*6185db85Sdougm * it is a valid path to be shared. NULL is returned on error 951*6185db85Sdougm * and a detailed error value will be returned via the error 952*6185db85Sdougm * pointer. 953*6185db85Sdougm */ 954*6185db85Sdougm sa_share_t 955*6185db85Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 956*6185db85Sdougm { 957*6185db85Sdougm xmlNodePtr node = NULL; 958*6185db85Sdougm sa_share_t dup; 959*6185db85Sdougm 960*6185db85Sdougm if ((dup = sa_find_share(sharepath)) == NULL && 961*6185db85Sdougm (*error = sa_check_path(group, sharepath)) == SA_OK) { 962*6185db85Sdougm node = _sa_add_share(group, sharepath, persist, error); 963*6185db85Sdougm } 964*6185db85Sdougm if (dup != NULL) 965*6185db85Sdougm *error = SA_DUPLICATE_NAME; 966*6185db85Sdougm 967*6185db85Sdougm return ((sa_share_t)node); 968*6185db85Sdougm } 969*6185db85Sdougm 970*6185db85Sdougm /* 971*6185db85Sdougm * sa_enable_share(share, protocol) 972*6185db85Sdougm * Enable the specified share to the specified protocol. 973*6185db85Sdougm * If protocol is NULL, then all protocols. 974*6185db85Sdougm */ 975*6185db85Sdougm int 976*6185db85Sdougm sa_enable_share(sa_share_t share, char *protocol) 977*6185db85Sdougm { 978*6185db85Sdougm char *sharepath; 979*6185db85Sdougm struct stat st; 980*6185db85Sdougm int err = 0; 981*6185db85Sdougm 982*6185db85Sdougm sharepath = sa_get_share_attr(share, "path"); 983*6185db85Sdougm if (stat(sharepath, &st) < 0) { 984*6185db85Sdougm err = SA_NO_SUCH_PATH; 985*6185db85Sdougm } else { 986*6185db85Sdougm /* tell the server about the share */ 987*6185db85Sdougm if (protocol != NULL) { 988*6185db85Sdougm /* lookup protocol specific handler */ 989*6185db85Sdougm err = sa_proto_share(protocol, share); 990*6185db85Sdougm if (err == SA_OK) 991*6185db85Sdougm (void) sa_set_share_attr(share, "shared", "true"); 992*6185db85Sdougm } else { 993*6185db85Sdougm /* tell all protocols */ 994*6185db85Sdougm err = sa_proto_share("nfs", share); /* only NFS for now */ 995*6185db85Sdougm (void) sa_set_share_attr(share, "shared", "true"); 996*6185db85Sdougm } 997*6185db85Sdougm } 998*6185db85Sdougm if (sharepath != NULL) 999*6185db85Sdougm sa_free_attr_string(sharepath); 1000*6185db85Sdougm return (err); 1001*6185db85Sdougm } 1002*6185db85Sdougm 1003*6185db85Sdougm /* 1004*6185db85Sdougm * sa_disable_share(share, protocol) 1005*6185db85Sdougm * Disable the specified share to the specified protocol. 1006*6185db85Sdougm * If protocol is NULL, then all protocols. 1007*6185db85Sdougm */ 1008*6185db85Sdougm int 1009*6185db85Sdougm sa_disable_share(sa_share_t share, char *protocol) 1010*6185db85Sdougm { 1011*6185db85Sdougm char *path; 1012*6185db85Sdougm char *shared; 1013*6185db85Sdougm int ret = SA_OK; 1014*6185db85Sdougm 1015*6185db85Sdougm path = sa_get_share_attr(share, "path"); 1016*6185db85Sdougm shared = sa_get_share_attr(share, "shared"); 1017*6185db85Sdougm 1018*6185db85Sdougm if (protocol != NULL) { 1019*6185db85Sdougm ret = sa_proto_unshare(protocol, path); 1020*6185db85Sdougm } else { 1021*6185db85Sdougm /* need to do all protocols */ 1022*6185db85Sdougm ret = sa_proto_unshare("nfs", path); 1023*6185db85Sdougm } 1024*6185db85Sdougm if (ret == SA_OK) 1025*6185db85Sdougm (void) sa_set_share_attr(share, "shared", NULL); 1026*6185db85Sdougm if (path != NULL) 1027*6185db85Sdougm sa_free_attr_string(path); 1028*6185db85Sdougm if (shared != NULL) 1029*6185db85Sdougm sa_free_attr_string(shared); 1030*6185db85Sdougm return (ret); 1031*6185db85Sdougm } 1032*6185db85Sdougm 1033*6185db85Sdougm /* 1034*6185db85Sdougm * sa_remove_share(share) 1035*6185db85Sdougm * 1036*6185db85Sdougm * remove the specified share from its containing group. 1037*6185db85Sdougm * Remove from the SMF or ZFS configuration space. 1038*6185db85Sdougm */ 1039*6185db85Sdougm 1040*6185db85Sdougm int 1041*6185db85Sdougm sa_remove_share(sa_share_t share) 1042*6185db85Sdougm { 1043*6185db85Sdougm sa_group_t group; 1044*6185db85Sdougm int ret = SA_OK; 1045*6185db85Sdougm char *type; 1046*6185db85Sdougm int transient = 0; 1047*6185db85Sdougm char *groupname; 1048*6185db85Sdougm char *zfs; 1049*6185db85Sdougm 1050*6185db85Sdougm type = sa_get_share_attr(share, "type"); 1051*6185db85Sdougm group = sa_get_parent_group(share); 1052*6185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 1053*6185db85Sdougm groupname = sa_get_group_attr(group, "name"); 1054*6185db85Sdougm if (type != NULL && strcmp(type, "persist") != 0) 1055*6185db85Sdougm transient = 1; 1056*6185db85Sdougm if (type != NULL) 1057*6185db85Sdougm sa_free_attr_string(type); 1058*6185db85Sdougm 1059*6185db85Sdougm /* remove the node from its group then free the memory */ 1060*6185db85Sdougm 1061*6185db85Sdougm /* 1062*6185db85Sdougm * need to test if "busy" 1063*6185db85Sdougm */ 1064*6185db85Sdougm /* only do SMF action if permanent */ 1065*6185db85Sdougm if (!transient || zfs != NULL) { 1066*6185db85Sdougm /* remove from legacy dfstab as well as possible SMF */ 1067*6185db85Sdougm ret = sa_delete_legacy(share); 1068*6185db85Sdougm if (ret == SA_OK) { 1069*6185db85Sdougm if (!sa_group_is_zfs(group)) { 1070*6185db85Sdougm ret = sa_delete_share(scf_handle, group, share); 1071*6185db85Sdougm } else { 1072*6185db85Sdougm char *sharepath = sa_get_share_attr(share, "path"); 1073*6185db85Sdougm if (sharepath != NULL) { 1074*6185db85Sdougm ret = sa_zfs_set_sharenfs(group, sharepath, 0); 1075*6185db85Sdougm sa_free_attr_string(sharepath); 1076*6185db85Sdougm } 1077*6185db85Sdougm } 1078*6185db85Sdougm } 1079*6185db85Sdougm } 1080*6185db85Sdougm if (groupname != NULL) 1081*6185db85Sdougm sa_free_attr_string(groupname); 1082*6185db85Sdougm if (zfs != NULL) 1083*6185db85Sdougm sa_free_attr_string(zfs); 1084*6185db85Sdougm 1085*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)share); 1086*6185db85Sdougm xmlFreeNode((xmlNodePtr)share); 1087*6185db85Sdougm return (ret); 1088*6185db85Sdougm } 1089*6185db85Sdougm 1090*6185db85Sdougm /* 1091*6185db85Sdougm * sa_move_share(group, share) 1092*6185db85Sdougm * 1093*6185db85Sdougm * move the specified share to the specified group. Update SMF 1094*6185db85Sdougm * appropriately. 1095*6185db85Sdougm */ 1096*6185db85Sdougm 1097*6185db85Sdougm int 1098*6185db85Sdougm sa_move_share(sa_group_t group, sa_share_t share) 1099*6185db85Sdougm { 1100*6185db85Sdougm sa_group_t oldgroup; 1101*6185db85Sdougm int ret = SA_OK; 1102*6185db85Sdougm 1103*6185db85Sdougm /* remove the node from its group then free the memory */ 1104*6185db85Sdougm 1105*6185db85Sdougm oldgroup = sa_get_parent_group(share); 1106*6185db85Sdougm if (oldgroup != group) { 1107*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)share); 1108*6185db85Sdougm /* now that the share isn't in its old group, add to the new one */ 1109*6185db85Sdougm xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 1110*6185db85Sdougm /* need to deal with SMF */ 1111*6185db85Sdougm if (ret == SA_OK) { 1112*6185db85Sdougm /* 1113*6185db85Sdougm * need to remove from old group first and then add to 1114*6185db85Sdougm * new group. Ideally, we would do the other order but 1115*6185db85Sdougm * need to avoid having the share in two groups at the 1116*6185db85Sdougm * same time. 1117*6185db85Sdougm */ 1118*6185db85Sdougm ret = sa_delete_share(scf_handle, oldgroup, share); 1119*6185db85Sdougm } 1120*6185db85Sdougm ret = sa_commit_share(scf_handle, group, share); 1121*6185db85Sdougm } 1122*6185db85Sdougm return (ret); 1123*6185db85Sdougm } 1124*6185db85Sdougm 1125*6185db85Sdougm /* 1126*6185db85Sdougm * sa_get_parent_group(share) 1127*6185db85Sdougm * 1128*6185db85Sdougm * Return the containg group for the share. If a group was actually 1129*6185db85Sdougm * passed in, we don't want a parent so return NULL. 1130*6185db85Sdougm */ 1131*6185db85Sdougm 1132*6185db85Sdougm sa_group_t 1133*6185db85Sdougm sa_get_parent_group(sa_share_t share) 1134*6185db85Sdougm { 1135*6185db85Sdougm xmlNodePtr node = NULL; 1136*6185db85Sdougm if (share != NULL) { 1137*6185db85Sdougm node = ((xmlNodePtr)share)->parent; 1138*6185db85Sdougm /* 1139*6185db85Sdougm * make sure parent is a group and not sharecfg since 1140*6185db85Sdougm * we may be cheating and passing in a group. 1141*6185db85Sdougm * Eventually, groups of groups might come into being. 1142*6185db85Sdougm */ 1143*6185db85Sdougm if (node == NULL || 1144*6185db85Sdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 1145*6185db85Sdougm node = NULL; 1146*6185db85Sdougm } 1147*6185db85Sdougm return ((sa_group_t)node); 1148*6185db85Sdougm } 1149*6185db85Sdougm 1150*6185db85Sdougm /* 1151*6185db85Sdougm * _sa_create_group(groupname) 1152*6185db85Sdougm * 1153*6185db85Sdougm * Create a group in the document. The caller will need to deal with 1154*6185db85Sdougm * configuration store and activation. 1155*6185db85Sdougm */ 1156*6185db85Sdougm 1157*6185db85Sdougm sa_group_t 1158*6185db85Sdougm _sa_create_group(char *groupname) 1159*6185db85Sdougm { 1160*6185db85Sdougm xmlNodePtr node = NULL; 1161*6185db85Sdougm 1162*6185db85Sdougm if (sa_valid_group_name(groupname)) { 1163*6185db85Sdougm node = xmlNewChild(sa_config_tree, NULL, 1164*6185db85Sdougm (xmlChar *)"group", NULL); 1165*6185db85Sdougm if (node != NULL) { 1166*6185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 1167*6185db85Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 1168*6185db85Sdougm } 1169*6185db85Sdougm } 1170*6185db85Sdougm return ((sa_group_t)node); 1171*6185db85Sdougm } 1172*6185db85Sdougm 1173*6185db85Sdougm /* 1174*6185db85Sdougm * _sa_create_zfs_group(group, groupname) 1175*6185db85Sdougm * 1176*6185db85Sdougm * Create a ZFS subgroup under the specified group. This may 1177*6185db85Sdougm * eventually form the basis of general sub-groups, but is currently 1178*6185db85Sdougm * restricted to ZFS. 1179*6185db85Sdougm */ 1180*6185db85Sdougm sa_group_t 1181*6185db85Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 1182*6185db85Sdougm { 1183*6185db85Sdougm xmlNodePtr node = NULL; 1184*6185db85Sdougm 1185*6185db85Sdougm node = xmlNewChild((xmlNodePtr)group, NULL, 1186*6185db85Sdougm (xmlChar *)"group", NULL); 1187*6185db85Sdougm if (node != NULL) { 1188*6185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 1189*6185db85Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 1190*6185db85Sdougm } 1191*6185db85Sdougm 1192*6185db85Sdougm return ((sa_group_t)node); 1193*6185db85Sdougm } 1194*6185db85Sdougm 1195*6185db85Sdougm /* 1196*6185db85Sdougm * sa_create_group(groupname, *error) 1197*6185db85Sdougm * 1198*6185db85Sdougm * Create a new group with groupname. Need to validate that it is a 1199*6185db85Sdougm * legal name for SMF and the construct the SMF service instance of 1200*6185db85Sdougm * svc:/network/shares/group to implement the group. All necessary 1201*6185db85Sdougm * operational properties must be added to the group at this point 1202*6185db85Sdougm * (via the SMF transaction model). 1203*6185db85Sdougm */ 1204*6185db85Sdougm sa_group_t 1205*6185db85Sdougm sa_create_group(char *groupname, int *error) 1206*6185db85Sdougm { 1207*6185db85Sdougm xmlNodePtr node = NULL; 1208*6185db85Sdougm sa_group_t group; 1209*6185db85Sdougm int ret; 1210*6185db85Sdougm char rbacstr[256]; 1211*6185db85Sdougm 1212*6185db85Sdougm ret = SA_OK; 1213*6185db85Sdougm 1214*6185db85Sdougm if (scf_handle == NULL) { 1215*6185db85Sdougm ret = SA_SYSTEM_ERR; 1216*6185db85Sdougm goto err; 1217*6185db85Sdougm } 1218*6185db85Sdougm 1219*6185db85Sdougm group = sa_get_group(groupname); 1220*6185db85Sdougm if (group != NULL) { 1221*6185db85Sdougm ret = SA_DUPLICATE_NAME; 1222*6185db85Sdougm } else { 1223*6185db85Sdougm if (sa_valid_group_name(groupname)) { 1224*6185db85Sdougm node = xmlNewChild(sa_config_tree, NULL, 1225*6185db85Sdougm (xmlChar *)"group", NULL); 1226*6185db85Sdougm if (node != NULL) { 1227*6185db85Sdougm xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname); 1228*6185db85Sdougm /* default to the group being enabled */ 1229*6185db85Sdougm xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled"); 1230*6185db85Sdougm ret = sa_create_instance(scf_handle, groupname); 1231*6185db85Sdougm if (ret == SA_OK) { 1232*6185db85Sdougm ret = sa_start_transaction(scf_handle, "operation"); 1233*6185db85Sdougm } 1234*6185db85Sdougm if (ret == SA_OK) { 1235*6185db85Sdougm ret = sa_set_property(scf_handle, "state", "enabled"); 1236*6185db85Sdougm if (ret == SA_OK) { 1237*6185db85Sdougm ret = sa_end_transaction(scf_handle); 1238*6185db85Sdougm } else { 1239*6185db85Sdougm sa_abort_transaction(scf_handle); 1240*6185db85Sdougm } 1241*6185db85Sdougm } 1242*6185db85Sdougm if (ret == SA_OK) { 1243*6185db85Sdougm /* initialize the RBAC strings */ 1244*6185db85Sdougm ret = sa_start_transaction(scf_handle, "general"); 1245*6185db85Sdougm if (ret == SA_OK) { 1246*6185db85Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 1247*6185db85Sdougm SA_RBAC_MANAGE, groupname); 1248*6185db85Sdougm ret = sa_set_property(scf_handle, 1249*6185db85Sdougm "action_authorization", 1250*6185db85Sdougm rbacstr); 1251*6185db85Sdougm } 1252*6185db85Sdougm if (ret == SA_OK) { 1253*6185db85Sdougm (void) snprintf(rbacstr, sizeof (rbacstr), "%s.%s", 1254*6185db85Sdougm SA_RBAC_VALUE, groupname); 1255*6185db85Sdougm ret = sa_set_property(scf_handle, 1256*6185db85Sdougm "value_authorization", 1257*6185db85Sdougm rbacstr); 1258*6185db85Sdougm } 1259*6185db85Sdougm if (ret == SA_OK) { 1260*6185db85Sdougm ret = sa_end_transaction(scf_handle); 1261*6185db85Sdougm } else { 1262*6185db85Sdougm sa_abort_transaction(scf_handle); 1263*6185db85Sdougm } 1264*6185db85Sdougm } 1265*6185db85Sdougm if (ret != SA_OK) { 1266*6185db85Sdougm /* 1267*6185db85Sdougm * Couldn't commit the group so we need to 1268*6185db85Sdougm * undo internally. 1269*6185db85Sdougm */ 1270*6185db85Sdougm xmlUnlinkNode(node); 1271*6185db85Sdougm xmlFreeNode(node); 1272*6185db85Sdougm node = NULL; 1273*6185db85Sdougm } 1274*6185db85Sdougm } else { 1275*6185db85Sdougm ret = SA_NO_MEMORY; 1276*6185db85Sdougm } 1277*6185db85Sdougm } else { 1278*6185db85Sdougm ret = SA_INVALID_NAME; 1279*6185db85Sdougm } 1280*6185db85Sdougm } 1281*6185db85Sdougm err: 1282*6185db85Sdougm if (error != NULL) 1283*6185db85Sdougm *error = ret; 1284*6185db85Sdougm return ((sa_group_t)node); 1285*6185db85Sdougm } 1286*6185db85Sdougm 1287*6185db85Sdougm /* 1288*6185db85Sdougm * sa_remove_group(group) 1289*6185db85Sdougm * 1290*6185db85Sdougm * Remove the specified group. This deletes from the SMF repository. 1291*6185db85Sdougm * All property groups and properties are removed. 1292*6185db85Sdougm */ 1293*6185db85Sdougm 1294*6185db85Sdougm int 1295*6185db85Sdougm sa_remove_group(sa_group_t group) 1296*6185db85Sdougm { 1297*6185db85Sdougm char *name; 1298*6185db85Sdougm int ret = SA_OK; 1299*6185db85Sdougm 1300*6185db85Sdougm name = sa_get_group_attr(group, "name"); 1301*6185db85Sdougm if (name != NULL) { 1302*6185db85Sdougm ret = sa_delete_instance(scf_handle, name); 1303*6185db85Sdougm sa_free_attr_string(name); 1304*6185db85Sdougm } 1305*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 1306*6185db85Sdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 1307*6185db85Sdougm return (ret); 1308*6185db85Sdougm } 1309*6185db85Sdougm 1310*6185db85Sdougm /* 1311*6185db85Sdougm * sa_update_config() 1312*6185db85Sdougm * 1313*6185db85Sdougm * Used to update legacy files that need to be updated in bulk 1314*6185db85Sdougm * Currently, this is a placeholder and will go away in a future 1315*6185db85Sdougm * release. 1316*6185db85Sdougm */ 1317*6185db85Sdougm 1318*6185db85Sdougm int 1319*6185db85Sdougm sa_update_config() 1320*6185db85Sdougm { 1321*6185db85Sdougm struct stat st; 1322*6185db85Sdougm 1323*6185db85Sdougm /* 1324*6185db85Sdougm * do legacy files first so we can tell when they change. 1325*6185db85Sdougm * This will go away when we start updating individual records 1326*6185db85Sdougm * rather than the whole file. 1327*6185db85Sdougm */ 1328*6185db85Sdougm update_legacy_config(); 1329*6185db85Sdougm /* update legacy timestamp */ 1330*6185db85Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) { 1331*6185db85Sdougm set_legacy_timestamp(sa_config_tree, SA_LEGACY_DFSTAB, 1332*6185db85Sdougm TSTAMP(st.st_ctim)); 1333*6185db85Sdougm } 1334*6185db85Sdougm return (SA_OK); 1335*6185db85Sdougm } 1336*6185db85Sdougm 1337*6185db85Sdougm /* 1338*6185db85Sdougm * get_node_attr(node, tag) 1339*6185db85Sdougm * 1340*6185db85Sdougm * Get the speficied tag(attribute) if it exists on the node. This is 1341*6185db85Sdougm * used internally by a number of attribute oriented functions. 1342*6185db85Sdougm */ 1343*6185db85Sdougm 1344*6185db85Sdougm static char * 1345*6185db85Sdougm get_node_attr(void *nodehdl, char *tag) 1346*6185db85Sdougm { 1347*6185db85Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 1348*6185db85Sdougm xmlChar *name = NULL; 1349*6185db85Sdougm 1350*6185db85Sdougm if (node != NULL) { 1351*6185db85Sdougm name = xmlGetProp(node, (xmlChar *)tag); 1352*6185db85Sdougm } 1353*6185db85Sdougm return ((char *)name); 1354*6185db85Sdougm } 1355*6185db85Sdougm 1356*6185db85Sdougm /* 1357*6185db85Sdougm * get_node_attr(node, tag) 1358*6185db85Sdougm * 1359*6185db85Sdougm * Set the speficied tag(attribute) to the specified value This is 1360*6185db85Sdougm * used internally by a number of attribute oriented functions. It 1361*6185db85Sdougm * doesn't update the repository, only the internal document state. 1362*6185db85Sdougm */ 1363*6185db85Sdougm 1364*6185db85Sdougm void 1365*6185db85Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 1366*6185db85Sdougm { 1367*6185db85Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 1368*6185db85Sdougm if (node != NULL && tag != NULL) { 1369*6185db85Sdougm if (value != NULL) { 1370*6185db85Sdougm xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value); 1371*6185db85Sdougm } else { 1372*6185db85Sdougm xmlUnsetProp(node, (xmlChar *)tag); 1373*6185db85Sdougm } 1374*6185db85Sdougm } 1375*6185db85Sdougm } 1376*6185db85Sdougm 1377*6185db85Sdougm /* 1378*6185db85Sdougm * sa_get_group_attr(group, tag) 1379*6185db85Sdougm * 1380*6185db85Sdougm * Get the specied attribute, if defined, for the group. 1381*6185db85Sdougm */ 1382*6185db85Sdougm 1383*6185db85Sdougm char * 1384*6185db85Sdougm sa_get_group_attr(sa_group_t group, char *tag) 1385*6185db85Sdougm { 1386*6185db85Sdougm return (get_node_attr((void *)group, tag)); 1387*6185db85Sdougm } 1388*6185db85Sdougm 1389*6185db85Sdougm /* 1390*6185db85Sdougm * sa_set_group_attr(group, tag, value) 1391*6185db85Sdougm * 1392*6185db85Sdougm * set the specified tag/attribute on the group using value as its 1393*6185db85Sdougm * value. 1394*6185db85Sdougm * 1395*6185db85Sdougm * This will result in setting the property in the SMF repository as 1396*6185db85Sdougm * well as in the internal document. 1397*6185db85Sdougm */ 1398*6185db85Sdougm 1399*6185db85Sdougm int 1400*6185db85Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 1401*6185db85Sdougm { 1402*6185db85Sdougm int ret; 1403*6185db85Sdougm char *groupname; 1404*6185db85Sdougm 1405*6185db85Sdougm groupname = sa_get_group_attr(group, "name"); 1406*6185db85Sdougm ret = sa_get_instance(scf_handle, groupname); 1407*6185db85Sdougm if (ret == SA_OK) { 1408*6185db85Sdougm set_node_attr((void *)group, tag, value); 1409*6185db85Sdougm ret = sa_start_transaction(scf_handle, "operation"); 1410*6185db85Sdougm if (ret == SA_OK) { 1411*6185db85Sdougm ret = sa_set_property(scf_handle, tag, value); 1412*6185db85Sdougm if (ret == SA_OK) 1413*6185db85Sdougm (void) sa_end_transaction(scf_handle); 1414*6185db85Sdougm else { 1415*6185db85Sdougm sa_abort_transaction(scf_handle); 1416*6185db85Sdougm } 1417*6185db85Sdougm } 1418*6185db85Sdougm } 1419*6185db85Sdougm if (groupname != NULL) 1420*6185db85Sdougm sa_free_attr_string(groupname); 1421*6185db85Sdougm return (ret); 1422*6185db85Sdougm } 1423*6185db85Sdougm 1424*6185db85Sdougm /* 1425*6185db85Sdougm * sa_get_share_attr(share, tag) 1426*6185db85Sdougm * 1427*6185db85Sdougm * Return the value of the tag/attribute set on the specified 1428*6185db85Sdougm * share. Returns NULL if the tag doesn't exist. 1429*6185db85Sdougm */ 1430*6185db85Sdougm 1431*6185db85Sdougm char * 1432*6185db85Sdougm sa_get_share_attr(sa_share_t share, char *tag) 1433*6185db85Sdougm { 1434*6185db85Sdougm return (get_node_attr((void *)share, tag)); 1435*6185db85Sdougm } 1436*6185db85Sdougm 1437*6185db85Sdougm /* 1438*6185db85Sdougm * sa_get_resource(group, resource) 1439*6185db85Sdougm * 1440*6185db85Sdougm * Search all the shares in the speified group for a share with a 1441*6185db85Sdougm * resource name matching the one specified. 1442*6185db85Sdougm * 1443*6185db85Sdougm * In the future, it may be advantageous to allow group to be NULL and 1444*6185db85Sdougm * search all groups but that isn't needed at present. 1445*6185db85Sdougm */ 1446*6185db85Sdougm 1447*6185db85Sdougm sa_share_t 1448*6185db85Sdougm sa_get_resource(sa_group_t group, char *resource) 1449*6185db85Sdougm { 1450*6185db85Sdougm sa_share_t share = NULL; 1451*6185db85Sdougm char *name = NULL; 1452*6185db85Sdougm 1453*6185db85Sdougm if (resource != NULL) { 1454*6185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 1455*6185db85Sdougm share = sa_get_next_share(share)) { 1456*6185db85Sdougm name = sa_get_share_attr(share, "resource"); 1457*6185db85Sdougm if (name != NULL) { 1458*6185db85Sdougm if (strcmp(name, resource) == 0) 1459*6185db85Sdougm break; 1460*6185db85Sdougm sa_free_attr_string(name); 1461*6185db85Sdougm name = NULL; 1462*6185db85Sdougm } 1463*6185db85Sdougm } 1464*6185db85Sdougm if (name != NULL) 1465*6185db85Sdougm sa_free_attr_string(name); 1466*6185db85Sdougm } 1467*6185db85Sdougm return ((sa_share_t)share); 1468*6185db85Sdougm } 1469*6185db85Sdougm 1470*6185db85Sdougm /* 1471*6185db85Sdougm * _sa_set_share_description(share, description) 1472*6185db85Sdougm * 1473*6185db85Sdougm * Add a description tag with text contents to the specified share. 1474*6185db85Sdougm * A separate XML tag is used rather than a property. 1475*6185db85Sdougm */ 1476*6185db85Sdougm 1477*6185db85Sdougm xmlNodePtr 1478*6185db85Sdougm _sa_set_share_description(sa_share_t share, char *content) 1479*6185db85Sdougm { 1480*6185db85Sdougm xmlNodePtr node; 1481*6185db85Sdougm node = xmlNewChild((xmlNodePtr)share, 1482*6185db85Sdougm NULL, (xmlChar *)"description", NULL); 1483*6185db85Sdougm xmlNodeSetContent(node, (xmlChar *)content); 1484*6185db85Sdougm return (node); 1485*6185db85Sdougm } 1486*6185db85Sdougm 1487*6185db85Sdougm /* 1488*6185db85Sdougm * sa_set_share_attr(share, tag, value) 1489*6185db85Sdougm * 1490*6185db85Sdougm * Set the share attribute specified by tag to the specified value. In 1491*6185db85Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 1492*6185db85Sdougm * the share is not transient, commit the changes to the repository 1493*6185db85Sdougm * else just update the share internally. 1494*6185db85Sdougm */ 1495*6185db85Sdougm 1496*6185db85Sdougm int 1497*6185db85Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 1498*6185db85Sdougm { 1499*6185db85Sdougm sa_group_t group; 1500*6185db85Sdougm sa_share_t resource; 1501*6185db85Sdougm int ret = SA_OK; 1502*6185db85Sdougm 1503*6185db85Sdougm group = sa_get_parent_group(share); 1504*6185db85Sdougm 1505*6185db85Sdougm /* 1506*6185db85Sdougm * There are some attributes that may have specific 1507*6185db85Sdougm * restrictions on them. Initially, only "resource" has 1508*6185db85Sdougm * special meaning that needs to be checked. Only one instance 1509*6185db85Sdougm * of a resource name may exist within a group. 1510*6185db85Sdougm */ 1511*6185db85Sdougm 1512*6185db85Sdougm if (strcmp(tag, "resource") == 0) { 1513*6185db85Sdougm resource = sa_get_resource(group, value); 1514*6185db85Sdougm if (resource != share && resource != NULL) 1515*6185db85Sdougm ret = SA_DUPLICATE_NAME; 1516*6185db85Sdougm } 1517*6185db85Sdougm if (ret == SA_OK) { 1518*6185db85Sdougm set_node_attr((void *)share, tag, value); 1519*6185db85Sdougm if (group != NULL) { 1520*6185db85Sdougm char *type; 1521*6185db85Sdougm /* we can probably optimize this some */ 1522*6185db85Sdougm type = sa_get_share_attr(share, "type"); 1523*6185db85Sdougm if (type == NULL || strcmp(type, "transient") != 0) 1524*6185db85Sdougm ret = sa_commit_share(scf_handle, group, share); 1525*6185db85Sdougm if (type != NULL) 1526*6185db85Sdougm sa_free_attr_string(type); 1527*6185db85Sdougm } 1528*6185db85Sdougm } 1529*6185db85Sdougm return (ret); 1530*6185db85Sdougm } 1531*6185db85Sdougm 1532*6185db85Sdougm /* 1533*6185db85Sdougm * sa_get_property_attr(prop, tag) 1534*6185db85Sdougm * 1535*6185db85Sdougm * Get the value of the specified property attribute. Standard 1536*6185db85Sdougm * attributes are "type" and "value". 1537*6185db85Sdougm */ 1538*6185db85Sdougm 1539*6185db85Sdougm char * 1540*6185db85Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 1541*6185db85Sdougm { 1542*6185db85Sdougm return (get_node_attr((void *)prop, tag)); 1543*6185db85Sdougm } 1544*6185db85Sdougm 1545*6185db85Sdougm /* 1546*6185db85Sdougm * sa_get_optionset_attr(prop, tag) 1547*6185db85Sdougm * 1548*6185db85Sdougm * Get the value of the specified property attribute. Standard 1549*6185db85Sdougm * attribute is "type". 1550*6185db85Sdougm */ 1551*6185db85Sdougm 1552*6185db85Sdougm char * 1553*6185db85Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 1554*6185db85Sdougm { 1555*6185db85Sdougm return (get_node_attr((void *)optionset, tag)); 1556*6185db85Sdougm 1557*6185db85Sdougm } 1558*6185db85Sdougm 1559*6185db85Sdougm /* 1560*6185db85Sdougm * sa_set_optionset_attr(optionset, tag, value) 1561*6185db85Sdougm * 1562*6185db85Sdougm * Set the specified attribute(tag) to the specified value on the 1563*6185db85Sdougm * optionset. 1564*6185db85Sdougm */ 1565*6185db85Sdougm 1566*6185db85Sdougm void 1567*6185db85Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 1568*6185db85Sdougm { 1569*6185db85Sdougm set_node_attr((void *)optionset, tag, value); 1570*6185db85Sdougm } 1571*6185db85Sdougm 1572*6185db85Sdougm /* 1573*6185db85Sdougm * sa_free_attr_string(string) 1574*6185db85Sdougm * 1575*6185db85Sdougm * Free the string that was returned in one of the sa_get_*_attr() 1576*6185db85Sdougm * functions. 1577*6185db85Sdougm */ 1578*6185db85Sdougm 1579*6185db85Sdougm void 1580*6185db85Sdougm sa_free_attr_string(char *string) 1581*6185db85Sdougm { 1582*6185db85Sdougm xmlFree((xmlChar *)string); 1583*6185db85Sdougm } 1584*6185db85Sdougm 1585*6185db85Sdougm /* 1586*6185db85Sdougm * sa_get_optionset(group, proto) 1587*6185db85Sdougm * 1588*6185db85Sdougm * Return the optionset, if it exists, that is associated with the 1589*6185db85Sdougm * specified protocol. 1590*6185db85Sdougm */ 1591*6185db85Sdougm 1592*6185db85Sdougm sa_optionset_t 1593*6185db85Sdougm sa_get_optionset(void *group, char *proto) 1594*6185db85Sdougm { 1595*6185db85Sdougm xmlNodePtr node; 1596*6185db85Sdougm xmlChar *value = NULL; 1597*6185db85Sdougm 1598*6185db85Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 1599*6185db85Sdougm node = node->next) { 1600*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 1601*6185db85Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 1602*6185db85Sdougm if (proto != NULL) { 1603*6185db85Sdougm if (value != NULL && 1604*6185db85Sdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 1605*6185db85Sdougm break; 1606*6185db85Sdougm } 1607*6185db85Sdougm if (value != NULL) { 1608*6185db85Sdougm xmlFree(value); 1609*6185db85Sdougm value = NULL; 1610*6185db85Sdougm } 1611*6185db85Sdougm } else { 1612*6185db85Sdougm break; 1613*6185db85Sdougm } 1614*6185db85Sdougm } 1615*6185db85Sdougm } 1616*6185db85Sdougm if (value != NULL) 1617*6185db85Sdougm xmlFree(value); 1618*6185db85Sdougm return ((sa_optionset_t)node); 1619*6185db85Sdougm } 1620*6185db85Sdougm 1621*6185db85Sdougm /* 1622*6185db85Sdougm * sa_get_next_optionset(optionset) 1623*6185db85Sdougm * 1624*6185db85Sdougm * Return the next optionset in the group. NULL if this was the last. 1625*6185db85Sdougm */ 1626*6185db85Sdougm 1627*6185db85Sdougm sa_optionset_t 1628*6185db85Sdougm sa_get_next_optionset(sa_optionset_t optionset) 1629*6185db85Sdougm { 1630*6185db85Sdougm xmlNodePtr node; 1631*6185db85Sdougm 1632*6185db85Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 1633*6185db85Sdougm node = node->next) { 1634*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 1635*6185db85Sdougm break; 1636*6185db85Sdougm } 1637*6185db85Sdougm } 1638*6185db85Sdougm return ((sa_optionset_t)node); 1639*6185db85Sdougm } 1640*6185db85Sdougm 1641*6185db85Sdougm /* 1642*6185db85Sdougm * sa_get_security(group, sectype, proto) 1643*6185db85Sdougm * 1644*6185db85Sdougm * Return the security optionset. The internal name is a hold over 1645*6185db85Sdougm * from the implementation and will be changed before the API is 1646*6185db85Sdougm * finalized. This is really a named optionset that can be negotiated 1647*6185db85Sdougm * as a group of properties (like NFS security options). 1648*6185db85Sdougm */ 1649*6185db85Sdougm 1650*6185db85Sdougm sa_security_t 1651*6185db85Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 1652*6185db85Sdougm { 1653*6185db85Sdougm xmlNodePtr node; 1654*6185db85Sdougm xmlChar *value = NULL; 1655*6185db85Sdougm 1656*6185db85Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 1657*6185db85Sdougm node = node->next) { 1658*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 1659*6185db85Sdougm if (proto != NULL) { 1660*6185db85Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 1661*6185db85Sdougm if (value == NULL || 1662*6185db85Sdougm (value != NULL && 1663*6185db85Sdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 1664*6185db85Sdougm /* it doesn't match so continue */ 1665*6185db85Sdougm xmlFree(value); 1666*6185db85Sdougm value = NULL; 1667*6185db85Sdougm continue; 1668*6185db85Sdougm } 1669*6185db85Sdougm } 1670*6185db85Sdougm if (value != NULL) { 1671*6185db85Sdougm xmlFree(value); 1672*6185db85Sdougm value = NULL; 1673*6185db85Sdougm } 1674*6185db85Sdougm /* potential match */ 1675*6185db85Sdougm if (sectype != NULL) { 1676*6185db85Sdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 1677*6185db85Sdougm if (value != NULL && 1678*6185db85Sdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 1679*6185db85Sdougm break; 1680*6185db85Sdougm } 1681*6185db85Sdougm } else { 1682*6185db85Sdougm break; 1683*6185db85Sdougm } 1684*6185db85Sdougm } 1685*6185db85Sdougm if (value != NULL) { 1686*6185db85Sdougm xmlFree(value); 1687*6185db85Sdougm value = NULL; 1688*6185db85Sdougm } 1689*6185db85Sdougm } 1690*6185db85Sdougm if (value != NULL) 1691*6185db85Sdougm xmlFree(value); 1692*6185db85Sdougm return ((sa_security_t)node); 1693*6185db85Sdougm } 1694*6185db85Sdougm 1695*6185db85Sdougm /* 1696*6185db85Sdougm * sa_get_next_security(security) 1697*6185db85Sdougm * 1698*6185db85Sdougm * Get the next security optionset if one exists. 1699*6185db85Sdougm */ 1700*6185db85Sdougm 1701*6185db85Sdougm sa_security_t 1702*6185db85Sdougm sa_get_next_security(sa_security_t security) 1703*6185db85Sdougm { 1704*6185db85Sdougm xmlNodePtr node; 1705*6185db85Sdougm 1706*6185db85Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 1707*6185db85Sdougm node = node->next) { 1708*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 1709*6185db85Sdougm break; 1710*6185db85Sdougm } 1711*6185db85Sdougm } 1712*6185db85Sdougm return ((sa_security_t)node); 1713*6185db85Sdougm } 1714*6185db85Sdougm 1715*6185db85Sdougm /* 1716*6185db85Sdougm * sa_get_property(optionset, prop) 1717*6185db85Sdougm * 1718*6185db85Sdougm * Get the property object with the name specified in prop from the 1719*6185db85Sdougm * optionset. 1720*6185db85Sdougm */ 1721*6185db85Sdougm 1722*6185db85Sdougm sa_property_t 1723*6185db85Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 1724*6185db85Sdougm { 1725*6185db85Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 1726*6185db85Sdougm xmlChar *value = NULL; 1727*6185db85Sdougm 1728*6185db85Sdougm if (optionset == NULL) 1729*6185db85Sdougm return (NULL); 1730*6185db85Sdougm 1731*6185db85Sdougm for (node = node->children; node != NULL; 1732*6185db85Sdougm node = node->next) { 1733*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 1734*6185db85Sdougm if (prop == NULL) 1735*6185db85Sdougm break; 1736*6185db85Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 1737*6185db85Sdougm if (value != NULL && xmlStrcmp(value, (xmlChar *)prop) == 0) { 1738*6185db85Sdougm break; 1739*6185db85Sdougm } 1740*6185db85Sdougm if (value != NULL) { 1741*6185db85Sdougm xmlFree(value); 1742*6185db85Sdougm value = NULL; 1743*6185db85Sdougm } 1744*6185db85Sdougm } 1745*6185db85Sdougm } 1746*6185db85Sdougm if (value != NULL) 1747*6185db85Sdougm xmlFree(value); 1748*6185db85Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 1749*6185db85Sdougm /* avoid a non option node -- it is possible to be a text node */ 1750*6185db85Sdougm node = NULL; 1751*6185db85Sdougm } 1752*6185db85Sdougm return ((sa_property_t)node); 1753*6185db85Sdougm } 1754*6185db85Sdougm 1755*6185db85Sdougm /* 1756*6185db85Sdougm * sa_get_next_property(property) 1757*6185db85Sdougm * 1758*6185db85Sdougm * Get the next property following the specified property. NULL if 1759*6185db85Sdougm * this was the last. 1760*6185db85Sdougm */ 1761*6185db85Sdougm 1762*6185db85Sdougm sa_property_t 1763*6185db85Sdougm sa_get_next_property(sa_property_t property) 1764*6185db85Sdougm { 1765*6185db85Sdougm xmlNodePtr node; 1766*6185db85Sdougm 1767*6185db85Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 1768*6185db85Sdougm node = node->next) { 1769*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 1770*6185db85Sdougm break; 1771*6185db85Sdougm } 1772*6185db85Sdougm } 1773*6185db85Sdougm return ((sa_property_t)node); 1774*6185db85Sdougm } 1775*6185db85Sdougm 1776*6185db85Sdougm /* 1777*6185db85Sdougm * sa_set_share_description(share, content) 1778*6185db85Sdougm * 1779*6185db85Sdougm * Set the description of share to content. 1780*6185db85Sdougm */ 1781*6185db85Sdougm 1782*6185db85Sdougm int 1783*6185db85Sdougm sa_set_share_description(sa_share_t share, char *content) 1784*6185db85Sdougm { 1785*6185db85Sdougm xmlNodePtr node; 1786*6185db85Sdougm sa_group_t group; 1787*6185db85Sdougm int ret = SA_OK; 1788*6185db85Sdougm 1789*6185db85Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 1790*6185db85Sdougm node = node->next) { 1791*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 1792*6185db85Sdougm break; 1793*6185db85Sdougm } 1794*6185db85Sdougm } 1795*6185db85Sdougm group = sa_get_parent_group(share); 1796*6185db85Sdougm /* no existing description but want to add */ 1797*6185db85Sdougm if (node == NULL && content != NULL) { 1798*6185db85Sdougm /* add a description */ 1799*6185db85Sdougm node = _sa_set_share_description(share, content); 1800*6185db85Sdougm } else if (node != NULL && content != NULL) { 1801*6185db85Sdougm /* update a description */ 1802*6185db85Sdougm xmlNodeSetContent(node, (xmlChar *)content); 1803*6185db85Sdougm } else if (node != NULL && content == NULL) { 1804*6185db85Sdougm /* remove an existing description */ 1805*6185db85Sdougm xmlUnlinkNode(node); 1806*6185db85Sdougm xmlFreeNode(node); 1807*6185db85Sdougm } 1808*6185db85Sdougm if (group != NULL && is_persistent((sa_group_t)share)) 1809*6185db85Sdougm ret = sa_commit_share(scf_handle, group, share); 1810*6185db85Sdougm return (ret); 1811*6185db85Sdougm } 1812*6185db85Sdougm 1813*6185db85Sdougm /* 1814*6185db85Sdougm * fixproblemchars(string) 1815*6185db85Sdougm * 1816*6185db85Sdougm * don't want any newline or tab characters in the text since these 1817*6185db85Sdougm * could break display of data and legacy file formats. 1818*6185db85Sdougm */ 1819*6185db85Sdougm static void 1820*6185db85Sdougm fixproblemchars(char *str) 1821*6185db85Sdougm { 1822*6185db85Sdougm int c; 1823*6185db85Sdougm for (c = *str; c != '\0'; c = *++str) { 1824*6185db85Sdougm if (c == '\t' || c == '\n') 1825*6185db85Sdougm *str = ' '; 1826*6185db85Sdougm else if (c == '"') 1827*6185db85Sdougm *str = '\''; 1828*6185db85Sdougm } 1829*6185db85Sdougm } 1830*6185db85Sdougm 1831*6185db85Sdougm /* 1832*6185db85Sdougm * sa_get_share_description(share) 1833*6185db85Sdougm * 1834*6185db85Sdougm * Return the description text for the specified share if it 1835*6185db85Sdougm * exists. NULL if no description exists. 1836*6185db85Sdougm */ 1837*6185db85Sdougm 1838*6185db85Sdougm char * 1839*6185db85Sdougm sa_get_share_description(sa_share_t share) 1840*6185db85Sdougm { 1841*6185db85Sdougm xmlChar *description = NULL; 1842*6185db85Sdougm xmlNodePtr node; 1843*6185db85Sdougm 1844*6185db85Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 1845*6185db85Sdougm node = node->next) { 1846*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 1847*6185db85Sdougm break; 1848*6185db85Sdougm } 1849*6185db85Sdougm } 1850*6185db85Sdougm if (node != NULL) { 1851*6185db85Sdougm description = xmlNodeGetContent((xmlNodePtr)share); 1852*6185db85Sdougm fixproblemchars((char *)description); 1853*6185db85Sdougm } 1854*6185db85Sdougm return ((char *)description); 1855*6185db85Sdougm } 1856*6185db85Sdougm 1857*6185db85Sdougm /* 1858*6185db85Sdougm * sa_free(share_description(description) 1859*6185db85Sdougm * 1860*6185db85Sdougm * Free the description string. 1861*6185db85Sdougm */ 1862*6185db85Sdougm 1863*6185db85Sdougm void 1864*6185db85Sdougm sa_free_share_description(char *description) 1865*6185db85Sdougm { 1866*6185db85Sdougm xmlFree((xmlChar *)description); 1867*6185db85Sdougm } 1868*6185db85Sdougm 1869*6185db85Sdougm /* 1870*6185db85Sdougm * sa_create_optionset(group, proto) 1871*6185db85Sdougm * 1872*6185db85Sdougm * Create an optionset for the specified protocol in the specied 1873*6185db85Sdougm * group. This is manifested as a property group within SMF. 1874*6185db85Sdougm */ 1875*6185db85Sdougm 1876*6185db85Sdougm sa_optionset_t 1877*6185db85Sdougm sa_create_optionset(sa_group_t group, char *proto) 1878*6185db85Sdougm { 1879*6185db85Sdougm sa_optionset_t optionset; 1880*6185db85Sdougm sa_group_t parent = group; 1881*6185db85Sdougm 1882*6185db85Sdougm optionset = sa_get_optionset(group, proto); 1883*6185db85Sdougm if (optionset != NULL) { 1884*6185db85Sdougm /* can't have a duplicate protocol */ 1885*6185db85Sdougm optionset = NULL; 1886*6185db85Sdougm } else { 1887*6185db85Sdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 1888*6185db85Sdougm NULL, 1889*6185db85Sdougm (xmlChar *)"optionset", 1890*6185db85Sdougm NULL); 1891*6185db85Sdougm /* 1892*6185db85Sdougm * only put to repository if on a group and we were 1893*6185db85Sdougm * able to create an optionset. 1894*6185db85Sdougm */ 1895*6185db85Sdougm if (optionset != NULL) { 1896*6185db85Sdougm char oname[256]; 1897*6185db85Sdougm char *groupname; 1898*6185db85Sdougm char *id = NULL; 1899*6185db85Sdougm 1900*6185db85Sdougm if (sa_is_share(group)) 1901*6185db85Sdougm parent = sa_get_parent_group((sa_share_t)group); 1902*6185db85Sdougm 1903*6185db85Sdougm sa_set_optionset_attr(optionset, "type", proto); 1904*6185db85Sdougm 1905*6185db85Sdougm if (sa_is_share(group)) { 1906*6185db85Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 1907*6185db85Sdougm } 1908*6185db85Sdougm (void) sa_optionset_name(optionset, oname, 1909*6185db85Sdougm sizeof (oname), id); 1910*6185db85Sdougm groupname = sa_get_group_attr(parent, "name"); 1911*6185db85Sdougm if (groupname != NULL && is_persistent(group)) { 1912*6185db85Sdougm (void) sa_get_instance(scf_handle, groupname); 1913*6185db85Sdougm sa_free_attr_string(groupname); 1914*6185db85Sdougm (void) sa_create_pgroup(scf_handle, oname); 1915*6185db85Sdougm } 1916*6185db85Sdougm if (id != NULL) 1917*6185db85Sdougm sa_free_attr_string(id); 1918*6185db85Sdougm } 1919*6185db85Sdougm } 1920*6185db85Sdougm return (optionset); 1921*6185db85Sdougm } 1922*6185db85Sdougm 1923*6185db85Sdougm /* 1924*6185db85Sdougm * sa_get_property_parent(property) 1925*6185db85Sdougm * 1926*6185db85Sdougm * Given a property, return the object it is a property of. This will 1927*6185db85Sdougm * be an optionset of some type. 1928*6185db85Sdougm */ 1929*6185db85Sdougm 1930*6185db85Sdougm static sa_optionset_t 1931*6185db85Sdougm sa_get_property_parent(sa_property_t property) 1932*6185db85Sdougm { 1933*6185db85Sdougm xmlNodePtr node = NULL; 1934*6185db85Sdougm 1935*6185db85Sdougm if (property != NULL) { 1936*6185db85Sdougm node = ((xmlNodePtr)property)->parent; 1937*6185db85Sdougm } 1938*6185db85Sdougm return ((sa_optionset_t)node); 1939*6185db85Sdougm } 1940*6185db85Sdougm 1941*6185db85Sdougm /* 1942*6185db85Sdougm * sa_get_optionset_parent(optionset) 1943*6185db85Sdougm * 1944*6185db85Sdougm * Return the parent of the specified optionset. This could be a group 1945*6185db85Sdougm * or a share. 1946*6185db85Sdougm */ 1947*6185db85Sdougm 1948*6185db85Sdougm static sa_group_t 1949*6185db85Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 1950*6185db85Sdougm { 1951*6185db85Sdougm xmlNodePtr node = NULL; 1952*6185db85Sdougm 1953*6185db85Sdougm if (optionset != NULL) { 1954*6185db85Sdougm node = ((xmlNodePtr)optionset)->parent; 1955*6185db85Sdougm } 1956*6185db85Sdougm return ((sa_group_t)node); 1957*6185db85Sdougm } 1958*6185db85Sdougm 1959*6185db85Sdougm /* 1960*6185db85Sdougm * zfs_needs_update(share) 1961*6185db85Sdougm * 1962*6185db85Sdougm * In order to avoid making multiple updates to a ZFS share when 1963*6185db85Sdougm * setting properties, the share attribute "changed" will be set to 1964*6185db85Sdougm * true when a property is added or modifed. When done adding 1965*6185db85Sdougm * properties, we can then detect that an update is needed. We then 1966*6185db85Sdougm * clear the state here to detect additional changes. 1967*6185db85Sdougm */ 1968*6185db85Sdougm 1969*6185db85Sdougm static int 1970*6185db85Sdougm zfs_needs_update(sa_share_t share) 1971*6185db85Sdougm { 1972*6185db85Sdougm char *attr; 1973*6185db85Sdougm int result = 0; 1974*6185db85Sdougm 1975*6185db85Sdougm attr = sa_get_share_attr(share, "changed"); 1976*6185db85Sdougm if (attr != NULL) { 1977*6185db85Sdougm sa_free_attr_string(attr); 1978*6185db85Sdougm result = 1; 1979*6185db85Sdougm } 1980*6185db85Sdougm set_node_attr((void *)share, "changed", NULL); 1981*6185db85Sdougm return (result); 1982*6185db85Sdougm } 1983*6185db85Sdougm 1984*6185db85Sdougm /* 1985*6185db85Sdougm * zfs_set_update(share) 1986*6185db85Sdougm * 1987*6185db85Sdougm * Set the changed attribute of the share to true. 1988*6185db85Sdougm */ 1989*6185db85Sdougm 1990*6185db85Sdougm static void 1991*6185db85Sdougm zfs_set_update(sa_share_t share) 1992*6185db85Sdougm { 1993*6185db85Sdougm set_node_attr((void *)share, "changed", "true"); 1994*6185db85Sdougm } 1995*6185db85Sdougm 1996*6185db85Sdougm /* 1997*6185db85Sdougm * sa_commit_properties(optionset, clear) 1998*6185db85Sdougm * 1999*6185db85Sdougm * Check if SMF or ZFS config and either update or abort the pending 2000*6185db85Sdougm * changes. 2001*6185db85Sdougm */ 2002*6185db85Sdougm 2003*6185db85Sdougm int 2004*6185db85Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 2005*6185db85Sdougm { 2006*6185db85Sdougm sa_group_t group; 2007*6185db85Sdougm sa_group_t parent; 2008*6185db85Sdougm int zfs = 0; 2009*6185db85Sdougm int needsupdate = 0; 2010*6185db85Sdougm int ret = SA_OK; 2011*6185db85Sdougm 2012*6185db85Sdougm group = sa_get_optionset_parent(optionset); 2013*6185db85Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 2014*6185db85Sdougm /* only update ZFS if on a share */ 2015*6185db85Sdougm parent = sa_get_parent_group(group); 2016*6185db85Sdougm zfs++; 2017*6185db85Sdougm if (parent != NULL && is_zfs_group(parent)) { 2018*6185db85Sdougm needsupdate = zfs_needs_update(group); 2019*6185db85Sdougm } else { 2020*6185db85Sdougm zfs = 0; 2021*6185db85Sdougm } 2022*6185db85Sdougm } 2023*6185db85Sdougm if (zfs) { 2024*6185db85Sdougm if (!clear && needsupdate) 2025*6185db85Sdougm ret = sa_zfs_update((sa_share_t)group); 2026*6185db85Sdougm } else { 2027*6185db85Sdougm if (clear) 2028*6185db85Sdougm (void) sa_abort_transaction(scf_handle); 2029*6185db85Sdougm else 2030*6185db85Sdougm ret = sa_end_transaction(scf_handle); 2031*6185db85Sdougm } 2032*6185db85Sdougm return (ret); 2033*6185db85Sdougm } 2034*6185db85Sdougm 2035*6185db85Sdougm /* 2036*6185db85Sdougm * sa_destroy_optionset(optionset) 2037*6185db85Sdougm * 2038*6185db85Sdougm * Remove the optionset from its group. Update the repostory to 2039*6185db85Sdougm * reflect this change. 2040*6185db85Sdougm */ 2041*6185db85Sdougm 2042*6185db85Sdougm int 2043*6185db85Sdougm sa_destroy_optionset(sa_optionset_t optionset) 2044*6185db85Sdougm { 2045*6185db85Sdougm char name[256]; 2046*6185db85Sdougm int len; 2047*6185db85Sdougm int ret; 2048*6185db85Sdougm char *id = NULL; 2049*6185db85Sdougm sa_group_t group; 2050*6185db85Sdougm int ispersist = 1; 2051*6185db85Sdougm 2052*6185db85Sdougm /* now delete the prop group */ 2053*6185db85Sdougm group = sa_get_optionset_parent(optionset); 2054*6185db85Sdougm if (group != NULL && sa_is_share(group)) { 2055*6185db85Sdougm ispersist = is_persistent(group); 2056*6185db85Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 2057*6185db85Sdougm } 2058*6185db85Sdougm if (ispersist) { 2059*6185db85Sdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 2060*6185db85Sdougm if (len > 0) { 2061*6185db85Sdougm ret = sa_delete_pgroup(scf_handle, name); 2062*6185db85Sdougm } 2063*6185db85Sdougm } 2064*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 2065*6185db85Sdougm xmlFreeNode((xmlNodePtr)optionset); 2066*6185db85Sdougm if (id != NULL) 2067*6185db85Sdougm sa_free_attr_string(id); 2068*6185db85Sdougm return (ret); 2069*6185db85Sdougm } 2070*6185db85Sdougm 2071*6185db85Sdougm /* private to the implementation */ 2072*6185db85Sdougm int 2073*6185db85Sdougm _sa_remove_optionset(sa_optionset_t optionset) 2074*6185db85Sdougm { 2075*6185db85Sdougm int ret = SA_OK; 2076*6185db85Sdougm 2077*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 2078*6185db85Sdougm xmlFreeNode((xmlNodePtr)optionset); 2079*6185db85Sdougm return (ret); 2080*6185db85Sdougm } 2081*6185db85Sdougm 2082*6185db85Sdougm /* 2083*6185db85Sdougm * sa_create_security(group, sectype, proto) 2084*6185db85Sdougm * 2085*6185db85Sdougm * Create a security optionset (one that has a type name and a 2086*6185db85Sdougm * proto). Security is left over from a pure NFS implementation. The 2087*6185db85Sdougm * naming will change in the future when the API is released. 2088*6185db85Sdougm */ 2089*6185db85Sdougm sa_security_t 2090*6185db85Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 2091*6185db85Sdougm { 2092*6185db85Sdougm sa_security_t security; 2093*6185db85Sdougm char *id = NULL; 2094*6185db85Sdougm sa_group_t parent; 2095*6185db85Sdougm char *groupname = NULL; 2096*6185db85Sdougm 2097*6185db85Sdougm if (group != NULL && sa_is_share(group)) { 2098*6185db85Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 2099*6185db85Sdougm parent = sa_get_parent_group(group); 2100*6185db85Sdougm if (parent != NULL) 2101*6185db85Sdougm groupname = sa_get_group_attr(parent, "name"); 2102*6185db85Sdougm } else if (group != NULL) { 2103*6185db85Sdougm groupname = sa_get_group_attr(group, "name"); 2104*6185db85Sdougm } 2105*6185db85Sdougm 2106*6185db85Sdougm security = sa_get_security(group, sectype, proto); 2107*6185db85Sdougm if (security != NULL) { 2108*6185db85Sdougm /* can't have a duplicate security option */ 2109*6185db85Sdougm security = NULL; 2110*6185db85Sdougm } else { 2111*6185db85Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 2112*6185db85Sdougm NULL, 2113*6185db85Sdougm (xmlChar *)"security", 2114*6185db85Sdougm NULL); 2115*6185db85Sdougm if (security != NULL) { 2116*6185db85Sdougm char oname[256]; 2117*6185db85Sdougm sa_set_security_attr(security, "type", proto); 2118*6185db85Sdougm 2119*6185db85Sdougm sa_set_security_attr(security, "sectype", sectype); 2120*6185db85Sdougm (void) sa_security_name(security, oname, 2121*6185db85Sdougm sizeof (oname), id); 2122*6185db85Sdougm if (groupname != NULL && is_persistent(group)) { 2123*6185db85Sdougm (void) sa_get_instance(scf_handle, groupname); 2124*6185db85Sdougm (void) sa_create_pgroup(scf_handle, oname); 2125*6185db85Sdougm } 2126*6185db85Sdougm } 2127*6185db85Sdougm } 2128*6185db85Sdougm if (groupname != NULL) 2129*6185db85Sdougm sa_free_attr_string(groupname); 2130*6185db85Sdougm return (security); 2131*6185db85Sdougm } 2132*6185db85Sdougm 2133*6185db85Sdougm /* 2134*6185db85Sdougm * sa_destroy_security(security) 2135*6185db85Sdougm * 2136*6185db85Sdougm * Remove the specified optionset from the document and the 2137*6185db85Sdougm * configuration. 2138*6185db85Sdougm */ 2139*6185db85Sdougm 2140*6185db85Sdougm int 2141*6185db85Sdougm sa_destroy_security(sa_security_t security) 2142*6185db85Sdougm { 2143*6185db85Sdougm char name[256]; 2144*6185db85Sdougm int len; 2145*6185db85Sdougm int ret = SA_OK; 2146*6185db85Sdougm char *id = NULL; 2147*6185db85Sdougm sa_group_t group; 2148*6185db85Sdougm int iszfs = 0; 2149*6185db85Sdougm int ispersist = 1; 2150*6185db85Sdougm 2151*6185db85Sdougm group = sa_get_optionset_parent(security); 2152*6185db85Sdougm 2153*6185db85Sdougm if (group != NULL) 2154*6185db85Sdougm iszfs = sa_group_is_zfs(group); 2155*6185db85Sdougm 2156*6185db85Sdougm if (group != NULL && !iszfs) { 2157*6185db85Sdougm if (sa_is_share(group)) 2158*6185db85Sdougm ispersist = is_persistent(group); 2159*6185db85Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 2160*6185db85Sdougm } 2161*6185db85Sdougm if (ispersist) { 2162*6185db85Sdougm len = sa_security_name(security, name, sizeof (name), id); 2163*6185db85Sdougm if (!iszfs && len > 0) { 2164*6185db85Sdougm ret = sa_delete_pgroup(scf_handle, name); 2165*6185db85Sdougm } 2166*6185db85Sdougm } 2167*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)security); 2168*6185db85Sdougm xmlFreeNode((xmlNodePtr)security); 2169*6185db85Sdougm if (iszfs) { 2170*6185db85Sdougm ret = sa_zfs_update(group); 2171*6185db85Sdougm } 2172*6185db85Sdougm if (id != NULL) 2173*6185db85Sdougm sa_free_attr_string(id); 2174*6185db85Sdougm return (ret); 2175*6185db85Sdougm } 2176*6185db85Sdougm 2177*6185db85Sdougm /* 2178*6185db85Sdougm * sa_get_security_attr(optionset, tag) 2179*6185db85Sdougm * 2180*6185db85Sdougm * Return the specified attribute value from the optionset. 2181*6185db85Sdougm */ 2182*6185db85Sdougm 2183*6185db85Sdougm char * 2184*6185db85Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 2185*6185db85Sdougm { 2186*6185db85Sdougm return (get_node_attr((void *)optionset, tag)); 2187*6185db85Sdougm 2188*6185db85Sdougm } 2189*6185db85Sdougm 2190*6185db85Sdougm /* 2191*6185db85Sdougm * sa_set_security_attr(optionset, tag, value) 2192*6185db85Sdougm * 2193*6185db85Sdougm * Set the optioset attribute specied by tag to the specified value. 2194*6185db85Sdougm */ 2195*6185db85Sdougm 2196*6185db85Sdougm void 2197*6185db85Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 2198*6185db85Sdougm { 2199*6185db85Sdougm set_node_attr((void *)optionset, tag, value); 2200*6185db85Sdougm } 2201*6185db85Sdougm 2202*6185db85Sdougm /* 2203*6185db85Sdougm * is_nodetype(node, type) 2204*6185db85Sdougm * 2205*6185db85Sdougm * Check to see if node is of the type specified. 2206*6185db85Sdougm */ 2207*6185db85Sdougm 2208*6185db85Sdougm static int 2209*6185db85Sdougm is_nodetype(void *node, char *type) 2210*6185db85Sdougm { 2211*6185db85Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 2212*6185db85Sdougm } 2213*6185db85Sdougm 2214*6185db85Sdougm /* 2215*6185db85Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 2216*6185db85Sdougm * 2217*6185db85Sdougm * Add/remove/update the specified property prop into the optionset or 2218*6185db85Sdougm * share. If a share, sort out which property group based on GUID. In 2219*6185db85Sdougm * all cases, the appropriate transaction is set (or ZFS share is 2220*6185db85Sdougm * marked as needing an update) 2221*6185db85Sdougm */ 2222*6185db85Sdougm 2223*6185db85Sdougm #define SA_PROP_OP_REMOVE 1 2224*6185db85Sdougm #define SA_PROP_OP_ADD 2 2225*6185db85Sdougm #define SA_PROP_OP_UPDATE 3 2226*6185db85Sdougm static int 2227*6185db85Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 2228*6185db85Sdougm sa_property_t prop, int type) 2229*6185db85Sdougm { 2230*6185db85Sdougm char *name; 2231*6185db85Sdougm char *valstr; 2232*6185db85Sdougm int ret = SA_OK; 2233*6185db85Sdougm scf_transaction_entry_t *entry; 2234*6185db85Sdougm scf_value_t *value; 2235*6185db85Sdougm int opttype; /* 1 == optionset, 0 == security */ 2236*6185db85Sdougm char *id = NULL; 2237*6185db85Sdougm int iszfs = 0; 2238*6185db85Sdougm int isshare = 0; 2239*6185db85Sdougm sa_group_t parent = NULL; 2240*6185db85Sdougm 2241*6185db85Sdougm if (!is_persistent(group)) { 2242*6185db85Sdougm /* 2243*6185db85Sdougm * if the group/share is not persistent we don't need 2244*6185db85Sdougm * to do anything here 2245*6185db85Sdougm */ 2246*6185db85Sdougm return (SA_OK); 2247*6185db85Sdougm } 2248*6185db85Sdougm name = sa_get_property_attr(prop, "type"); 2249*6185db85Sdougm valstr = sa_get_property_attr(prop, "value"); 2250*6185db85Sdougm entry = scf_entry_create(scf_handle->handle); 2251*6185db85Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 2252*6185db85Sdougm 2253*6185db85Sdougm if (valstr != NULL && entry != NULL) { 2254*6185db85Sdougm if (sa_is_share(group)) { 2255*6185db85Sdougm isshare = 1; 2256*6185db85Sdougm parent = sa_get_parent_group(group); 2257*6185db85Sdougm if (parent != NULL) { 2258*6185db85Sdougm iszfs = is_zfs_group(parent); 2259*6185db85Sdougm } 2260*6185db85Sdougm } else { 2261*6185db85Sdougm iszfs = is_zfs_group(group); 2262*6185db85Sdougm } 2263*6185db85Sdougm if (!iszfs) { 2264*6185db85Sdougm if (scf_handle->trans == NULL) { 2265*6185db85Sdougm char oname[256]; 2266*6185db85Sdougm char *groupname = NULL; 2267*6185db85Sdougm if (isshare) { 2268*6185db85Sdougm if (parent != NULL) { 2269*6185db85Sdougm groupname = sa_get_group_attr(parent, "name"); 2270*6185db85Sdougm } 2271*6185db85Sdougm id = sa_get_share_attr((sa_share_t)group, "id"); 2272*6185db85Sdougm } else { 2273*6185db85Sdougm groupname = sa_get_group_attr(group, "name"); 2274*6185db85Sdougm } 2275*6185db85Sdougm if (groupname != NULL) { 2276*6185db85Sdougm ret = sa_get_instance(scf_handle, groupname); 2277*6185db85Sdougm sa_free_attr_string(groupname); 2278*6185db85Sdougm } 2279*6185db85Sdougm if (opttype) 2280*6185db85Sdougm (void) sa_optionset_name(optionset, oname, 2281*6185db85Sdougm sizeof (oname), id); 2282*6185db85Sdougm else 2283*6185db85Sdougm (void) sa_security_name(optionset, oname, 2284*6185db85Sdougm sizeof (oname), id); 2285*6185db85Sdougm ret = sa_start_transaction(scf_handle, oname); 2286*6185db85Sdougm } 2287*6185db85Sdougm if (ret == SA_OK) { 2288*6185db85Sdougm switch (type) { 2289*6185db85Sdougm case SA_PROP_OP_REMOVE: 2290*6185db85Sdougm ret = scf_transaction_property_delete(scf_handle->trans, 2291*6185db85Sdougm entry, 2292*6185db85Sdougm name); 2293*6185db85Sdougm break; 2294*6185db85Sdougm case SA_PROP_OP_ADD: 2295*6185db85Sdougm case SA_PROP_OP_UPDATE: 2296*6185db85Sdougm value = scf_value_create(scf_handle->handle); 2297*6185db85Sdougm if (value != NULL) { 2298*6185db85Sdougm if (type == SA_PROP_OP_ADD) 2299*6185db85Sdougm ret = scf_transaction_property_new( 2300*6185db85Sdougm scf_handle->trans, 2301*6185db85Sdougm entry, 2302*6185db85Sdougm name, 2303*6185db85Sdougm SCF_TYPE_ASTRING); 2304*6185db85Sdougm else 2305*6185db85Sdougm ret = scf_transaction_property_change( 2306*6185db85Sdougm scf_handle->trans, 2307*6185db85Sdougm entry, 2308*6185db85Sdougm name, 2309*6185db85Sdougm SCF_TYPE_ASTRING); 2310*6185db85Sdougm if (ret == 0) { 2311*6185db85Sdougm ret = scf_value_set_astring(value, valstr); 2312*6185db85Sdougm if (ret == 0) 2313*6185db85Sdougm ret = scf_entry_add_value(entry, value); 2314*6185db85Sdougm if (ret != 0) { 2315*6185db85Sdougm scf_value_destroy(value); 2316*6185db85Sdougm ret = SA_SYSTEM_ERR; 2317*6185db85Sdougm } 2318*6185db85Sdougm } else { 2319*6185db85Sdougm scf_entry_destroy(entry); 2320*6185db85Sdougm ret = SA_SYSTEM_ERR; 2321*6185db85Sdougm } 2322*6185db85Sdougm break; 2323*6185db85Sdougm } 2324*6185db85Sdougm } 2325*6185db85Sdougm } 2326*6185db85Sdougm } else { 2327*6185db85Sdougm /* 2328*6185db85Sdougm * ZFS update. The calling function would have updated 2329*6185db85Sdougm * the internal XML structure. Just need to flag it as 2330*6185db85Sdougm * changed for ZFS. 2331*6185db85Sdougm */ 2332*6185db85Sdougm zfs_set_update((sa_share_t)group); 2333*6185db85Sdougm } 2334*6185db85Sdougm } 2335*6185db85Sdougm 2336*6185db85Sdougm if (name != NULL) 2337*6185db85Sdougm sa_free_attr_string(name); 2338*6185db85Sdougm if (valstr != NULL) 2339*6185db85Sdougm sa_free_attr_string(valstr); 2340*6185db85Sdougm else if (entry != NULL) 2341*6185db85Sdougm scf_entry_destroy(entry); 2342*6185db85Sdougm 2343*6185db85Sdougm if (ret == -1) 2344*6185db85Sdougm ret = SA_SYSTEM_ERR; 2345*6185db85Sdougm 2346*6185db85Sdougm return (ret); 2347*6185db85Sdougm } 2348*6185db85Sdougm 2349*6185db85Sdougm /* 2350*6185db85Sdougm * sa_create_property(name, value) 2351*6185db85Sdougm * 2352*6185db85Sdougm * Create a new property with the specified name and value. 2353*6185db85Sdougm */ 2354*6185db85Sdougm 2355*6185db85Sdougm sa_property_t 2356*6185db85Sdougm sa_create_property(char *name, char *value) 2357*6185db85Sdougm { 2358*6185db85Sdougm xmlNodePtr node; 2359*6185db85Sdougm 2360*6185db85Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 2361*6185db85Sdougm if (node != NULL) { 2362*6185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 2363*6185db85Sdougm xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 2364*6185db85Sdougm } 2365*6185db85Sdougm return ((sa_property_t)node); 2366*6185db85Sdougm } 2367*6185db85Sdougm 2368*6185db85Sdougm /* 2369*6185db85Sdougm * sa_add_property(object, property) 2370*6185db85Sdougm * 2371*6185db85Sdougm * Add the specified property to the object. Issue the appropriate 2372*6185db85Sdougm * transaction or mark a ZFS object as needing an update. 2373*6185db85Sdougm */ 2374*6185db85Sdougm 2375*6185db85Sdougm int 2376*6185db85Sdougm sa_add_property(void *object, sa_property_t property) 2377*6185db85Sdougm { 2378*6185db85Sdougm int ret = SA_OK; 2379*6185db85Sdougm sa_group_t parent; 2380*6185db85Sdougm sa_group_t group; 2381*6185db85Sdougm char *proto; 2382*6185db85Sdougm 2383*6185db85Sdougm proto = sa_get_optionset_attr(object, "type"); 2384*6185db85Sdougm if (property != NULL) { 2385*6185db85Sdougm if ((ret = sa_valid_property(object, proto, property)) == SA_OK) { 2386*6185db85Sdougm property = (sa_property_t)xmlAddChild((xmlNodePtr)object, 2387*6185db85Sdougm (xmlNodePtr)property); 2388*6185db85Sdougm } else { 2389*6185db85Sdougm if (proto != NULL) 2390*6185db85Sdougm sa_free_attr_string(proto); 2391*6185db85Sdougm return (ret); 2392*6185db85Sdougm } 2393*6185db85Sdougm } 2394*6185db85Sdougm 2395*6185db85Sdougm if (proto != NULL) 2396*6185db85Sdougm sa_free_attr_string(proto); 2397*6185db85Sdougm 2398*6185db85Sdougm parent = sa_get_parent_group(object); 2399*6185db85Sdougm if (!is_persistent(parent)) { 2400*6185db85Sdougm return (ret); 2401*6185db85Sdougm } 2402*6185db85Sdougm 2403*6185db85Sdougm if (sa_is_share(parent)) 2404*6185db85Sdougm group = sa_get_parent_group(parent); 2405*6185db85Sdougm else 2406*6185db85Sdougm group = parent; 2407*6185db85Sdougm 2408*6185db85Sdougm if (property == NULL) 2409*6185db85Sdougm ret = SA_NO_MEMORY; 2410*6185db85Sdougm else { 2411*6185db85Sdougm char oname[256]; 2412*6185db85Sdougm 2413*6185db85Sdougm if (!is_zfs_group(group)) { 2414*6185db85Sdougm char *id = NULL; 2415*6185db85Sdougm if (sa_is_share((sa_group_t)parent)) { 2416*6185db85Sdougm id = sa_get_share_attr((sa_share_t)parent, "id"); 2417*6185db85Sdougm } 2418*6185db85Sdougm if (scf_handle->trans == NULL) { 2419*6185db85Sdougm if (is_nodetype(object, "optionset")) 2420*6185db85Sdougm (void) sa_optionset_name((sa_optionset_t)object, 2421*6185db85Sdougm oname, sizeof (oname), id); 2422*6185db85Sdougm else 2423*6185db85Sdougm (void) sa_security_name((sa_optionset_t)object, 2424*6185db85Sdougm oname, sizeof (oname), id); 2425*6185db85Sdougm ret = sa_start_transaction(scf_handle, oname); 2426*6185db85Sdougm } 2427*6185db85Sdougm if (ret == SA_OK) { 2428*6185db85Sdougm char *name; 2429*6185db85Sdougm char *value; 2430*6185db85Sdougm name = sa_get_property_attr(property, "type"); 2431*6185db85Sdougm value = sa_get_property_attr(property, "value"); 2432*6185db85Sdougm if (name != NULL && value != NULL) { 2433*6185db85Sdougm if (scf_handle->scf_state == SCH_STATE_INIT) 2434*6185db85Sdougm ret = sa_set_property(scf_handle, name, value); 2435*6185db85Sdougm } else 2436*6185db85Sdougm ret = SA_CONFIG_ERR; 2437*6185db85Sdougm if (name != NULL) 2438*6185db85Sdougm sa_free_attr_string(name); 2439*6185db85Sdougm if (value != NULL) 2440*6185db85Sdougm sa_free_attr_string(value); 2441*6185db85Sdougm } 2442*6185db85Sdougm if (id != NULL) 2443*6185db85Sdougm sa_free_attr_string(id); 2444*6185db85Sdougm } else { 2445*6185db85Sdougm /* 2446*6185db85Sdougm * ZFS is a special case. We do want to allow editing 2447*6185db85Sdougm * property/security lists since we can have a better 2448*6185db85Sdougm * syntax and we also want to keep things consistent 2449*6185db85Sdougm * when possible. 2450*6185db85Sdougm * 2451*6185db85Sdougm * Right now, we defer until the sa_commit_properties 2452*6185db85Sdougm * so we can get them all at once. We do need to mark 2453*6185db85Sdougm * the share as "changed" 2454*6185db85Sdougm */ 2455*6185db85Sdougm zfs_set_update((sa_share_t)parent); 2456*6185db85Sdougm } 2457*6185db85Sdougm } 2458*6185db85Sdougm return (ret); 2459*6185db85Sdougm } 2460*6185db85Sdougm 2461*6185db85Sdougm /* 2462*6185db85Sdougm * sa_remove_property(property) 2463*6185db85Sdougm * 2464*6185db85Sdougm * Remove the specied property from its containing object. Update the 2465*6185db85Sdougm * repository as appropriate. 2466*6185db85Sdougm */ 2467*6185db85Sdougm 2468*6185db85Sdougm int 2469*6185db85Sdougm sa_remove_property(sa_property_t property) 2470*6185db85Sdougm { 2471*6185db85Sdougm int ret = SA_OK; 2472*6185db85Sdougm 2473*6185db85Sdougm if (property != NULL) { 2474*6185db85Sdougm sa_optionset_t optionset; 2475*6185db85Sdougm sa_group_t group; 2476*6185db85Sdougm optionset = sa_get_property_parent(property); 2477*6185db85Sdougm if (optionset != NULL) { 2478*6185db85Sdougm group = sa_get_optionset_parent(optionset); 2479*6185db85Sdougm if (group != NULL) { 2480*6185db85Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 2481*6185db85Sdougm SA_PROP_OP_REMOVE); 2482*6185db85Sdougm } 2483*6185db85Sdougm } 2484*6185db85Sdougm xmlUnlinkNode((xmlNodePtr)property); 2485*6185db85Sdougm xmlFreeNode((xmlNodePtr)property); 2486*6185db85Sdougm } else { 2487*6185db85Sdougm ret = SA_NO_SUCH_PROP; 2488*6185db85Sdougm } 2489*6185db85Sdougm return (ret); 2490*6185db85Sdougm } 2491*6185db85Sdougm 2492*6185db85Sdougm /* 2493*6185db85Sdougm * sa_update_property(property, value) 2494*6185db85Sdougm * 2495*6185db85Sdougm * Update the specified property to the new value. If value is NULL, 2496*6185db85Sdougm * we currently treat this as a remove. 2497*6185db85Sdougm */ 2498*6185db85Sdougm 2499*6185db85Sdougm int 2500*6185db85Sdougm sa_update_property(sa_property_t property, char *value) 2501*6185db85Sdougm { 2502*6185db85Sdougm int ret = SA_OK; 2503*6185db85Sdougm if (value == NULL) { 2504*6185db85Sdougm return (sa_remove_property(property)); 2505*6185db85Sdougm } else { 2506*6185db85Sdougm sa_optionset_t optionset; 2507*6185db85Sdougm sa_group_t group; 2508*6185db85Sdougm set_node_attr((void *)property, "value", value); 2509*6185db85Sdougm optionset = sa_get_property_parent(property); 2510*6185db85Sdougm if (optionset != NULL) { 2511*6185db85Sdougm group = sa_get_optionset_parent(optionset); 2512*6185db85Sdougm if (group != NULL) { 2513*6185db85Sdougm ret = sa_set_prop_by_prop(optionset, group, property, 2514*6185db85Sdougm SA_PROP_OP_UPDATE); 2515*6185db85Sdougm } 2516*6185db85Sdougm } else { 2517*6185db85Sdougm ret = SA_NO_SUCH_PROP; 2518*6185db85Sdougm } 2519*6185db85Sdougm } 2520*6185db85Sdougm return (ret); 2521*6185db85Sdougm } 2522*6185db85Sdougm 2523*6185db85Sdougm /* 2524*6185db85Sdougm * _sa_get_next_error(node) 2525*6185db85Sdougm * 2526*6185db85Sdougm * Get the next (first if node==NULL) error node in the 2527*6185db85Sdougm * document. "error" nodes are added if there were syntax errors 2528*6185db85Sdougm * during parsing of the /etc/dfs/dfstab file. They are preserved in 2529*6185db85Sdougm * comments and recreated in the doc on the next parse. 2530*6185db85Sdougm */ 2531*6185db85Sdougm 2532*6185db85Sdougm xmlNodePtr 2533*6185db85Sdougm _sa_get_next_error(xmlNodePtr node) 2534*6185db85Sdougm { 2535*6185db85Sdougm if (node == NULL) { 2536*6185db85Sdougm for (node = sa_config_tree->xmlChildrenNode; 2537*6185db85Sdougm node != NULL; node = node->next) 2538*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 2539*6185db85Sdougm return (node); 2540*6185db85Sdougm } else { 2541*6185db85Sdougm for (node = node->next; node != NULL; node = node->next) 2542*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"error") == 0) 2543*6185db85Sdougm return (node); 2544*6185db85Sdougm } 2545*6185db85Sdougm return (node); 2546*6185db85Sdougm } 2547*6185db85Sdougm 2548*6185db85Sdougm /* 2549*6185db85Sdougm * sa_get_protocol_property(propset, prop) 2550*6185db85Sdougm * 2551*6185db85Sdougm * Get the specified protocol specific property. These are global to 2552*6185db85Sdougm * the protocol and not specific to a group or share. 2553*6185db85Sdougm */ 2554*6185db85Sdougm 2555*6185db85Sdougm sa_property_t 2556*6185db85Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 2557*6185db85Sdougm { 2558*6185db85Sdougm xmlNodePtr node = (xmlNodePtr)propset; 2559*6185db85Sdougm xmlChar *value = NULL; 2560*6185db85Sdougm 2561*6185db85Sdougm for (node = node->children; node != NULL; 2562*6185db85Sdougm node = node->next) { 2563*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 2564*6185db85Sdougm if (prop == NULL) 2565*6185db85Sdougm break; 2566*6185db85Sdougm value = xmlGetProp(node, (xmlChar *)"type"); 2567*6185db85Sdougm if (value != NULL && 2568*6185db85Sdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 2569*6185db85Sdougm break; 2570*6185db85Sdougm } 2571*6185db85Sdougm if (value != NULL) { 2572*6185db85Sdougm xmlFree(value); 2573*6185db85Sdougm value = NULL; 2574*6185db85Sdougm } 2575*6185db85Sdougm } 2576*6185db85Sdougm } 2577*6185db85Sdougm if (value != NULL) 2578*6185db85Sdougm xmlFree(value); 2579*6185db85Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 2580*6185db85Sdougm /* avoid a non option node -- it is possible to be a text node */ 2581*6185db85Sdougm node = NULL; 2582*6185db85Sdougm } 2583*6185db85Sdougm return ((sa_property_t)node); 2584*6185db85Sdougm } 2585*6185db85Sdougm 2586*6185db85Sdougm /* 2587*6185db85Sdougm * sa_get_next_protocol_property(prop) 2588*6185db85Sdougm * 2589*6185db85Sdougm * Get the next protocol specific property in the list. 2590*6185db85Sdougm */ 2591*6185db85Sdougm 2592*6185db85Sdougm sa_property_t 2593*6185db85Sdougm sa_get_next_protocol_property(sa_property_t prop) 2594*6185db85Sdougm { 2595*6185db85Sdougm xmlNodePtr node; 2596*6185db85Sdougm 2597*6185db85Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 2598*6185db85Sdougm node = node->next) { 2599*6185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 2600*6185db85Sdougm break; 2601*6185db85Sdougm } 2602*6185db85Sdougm } 2603*6185db85Sdougm return ((sa_property_t)node); 2604*6185db85Sdougm } 2605*6185db85Sdougm 2606*6185db85Sdougm /* 2607*6185db85Sdougm * sa_set_protocol_property(prop, value) 2608*6185db85Sdougm * 2609*6185db85Sdougm * Set the specified property to have the new value. The protocol 2610*6185db85Sdougm * specific plugin will then be called to update the property. 2611*6185db85Sdougm */ 2612*6185db85Sdougm 2613*6185db85Sdougm int 2614*6185db85Sdougm sa_set_protocol_property(sa_property_t prop, char *value) 2615*6185db85Sdougm { 2616*6185db85Sdougm sa_protocol_properties_t propset; 2617*6185db85Sdougm char *proto; 2618*6185db85Sdougm int ret = SA_INVALID_PROTOCOL; 2619*6185db85Sdougm 2620*6185db85Sdougm propset = ((xmlNodePtr)prop)->parent; 2621*6185db85Sdougm if (propset != NULL) { 2622*6185db85Sdougm proto = sa_get_optionset_attr(propset, "type"); 2623*6185db85Sdougm if (proto != NULL) { 2624*6185db85Sdougm set_node_attr((xmlNodePtr)prop, "value", value); 2625*6185db85Sdougm ret = sa_proto_set_property(proto, prop); 2626*6185db85Sdougm sa_free_attr_string(prop); 2627*6185db85Sdougm } 2628*6185db85Sdougm } 2629*6185db85Sdougm return (ret); 2630*6185db85Sdougm } 2631*6185db85Sdougm 2632*6185db85Sdougm /* 2633*6185db85Sdougm * sa_add_protocol_property(propset, prop) 2634*6185db85Sdougm * 2635*6185db85Sdougm * Add a new property to the protocol sepcific property set. 2636*6185db85Sdougm */ 2637*6185db85Sdougm 2638*6185db85Sdougm int 2639*6185db85Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 2640*6185db85Sdougm { 2641*6185db85Sdougm xmlNodePtr node; 2642*6185db85Sdougm 2643*6185db85Sdougm /* should check for legitimacy */ 2644*6185db85Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 2645*6185db85Sdougm if (node != NULL) 2646*6185db85Sdougm return (SA_OK); 2647*6185db85Sdougm return (SA_NO_MEMORY); 2648*6185db85Sdougm } 2649*6185db85Sdougm 2650*6185db85Sdougm /* 2651*6185db85Sdougm * sa_create_protocol_properties(proto) 2652*6185db85Sdougm * 2653*6185db85Sdougm * Create a protocol specifity property set. 2654*6185db85Sdougm */ 2655*6185db85Sdougm 2656*6185db85Sdougm sa_protocol_properties_t 2657*6185db85Sdougm sa_create_protocol_properties(char *proto) 2658*6185db85Sdougm { 2659*6185db85Sdougm xmlNodePtr node; 2660*6185db85Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 2661*6185db85Sdougm if (node != NULL) { 2662*6185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 2663*6185db85Sdougm } 2664*6185db85Sdougm return (node); 2665*6185db85Sdougm } 2666