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