2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * This file converts shares in libshare v1 format to libshare v2 format.
2N/A * The configuration of libshare v1 shares is stored in the
2N/A * svc:/network/shares/group:<groupname> SMF service instances.
2N/A * This configuration is read and converted into nvlist format of
2N/A * libshare v2. Additionally, libshare v1 has the concept of groups, shares and
2N/A * resources. Groups can contain shares and shares can have different resource
2N/A * names. Properties can be defined at each of the 3 levels described above.
2N/A * The group properties are inherited by shares and the share properties are
2N/A * inherited by resources.
2N/A *
2N/A * We start out by parsing out the SMF configuration of the share into a
2N/A * nvlist format. We then merge the group and share properties
2N/A * into the newly defined nvlist share for libshare v2.
2N/A *
2N/A * Example
2N/A * -------
2N/A *
2N/A * Consider a share defined in libshare v1 format. The share belongs to group
2N/A * named "smb". This group has "rw=*" property setting. The shared path is
2N/A * /export/home and it has "none=*" property setting. The share is
2N/A * named with resource name "exp" and has a description of "comment".
2N/A * Additionally the resource has "rw=.CIFSDEVDC, abe=true, csc=manual"
2N/A * properties.
2N/A *
2N/A * smb smb=(rw="*")
2N/A * /export/home smb=(none="*")
2N/A * exp=/export/home smb=(rw=".CIFSDEVDC" abe="true" csc="manual") "comment"
2N/A *
2N/A * Format of the share in SMF configuration
2N/A * ----------------------------------------
2N/A *
2N/A * Group names start with "optionset" and share and resource names
2N/A * start with "S-". The share (with path "/export/home") with resource name
2N/A * "exp" belongs to the "smb" group.
2N/A *
2N/A * svc:/network/shares/group:smb> listprop
2N/A * :
2N/A * optionset_smb application
2N/A * optionset_smb/rw astring *
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582 application
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582/path astring /export/home
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582/resource astring "1:exp:comment"
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1 application
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1/rw astring .CIFSDEVDC
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1/abe astring true
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1/csc astring manual
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582_smb application
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582_smb/none astring *
2N/A *
2N/A * Format of the nvlist that is created from the share in SMF
2N/A * ----------------------------------------------------------
2N/A *
2N/A * The SMF configuration is parsed into a nvlist. Below is the output of the
2N/A * nvlist created by parsing the SMF configuration of the share.
2N/A *
2N/A * sharecfg:
2N/A * smb:
2N/A * gname: smb
2N/A * smb:
2N/A * rw: *
2N/A * S-d49965d5-a91b-4b40-996d-bff3e535e582:
2N/A * id: S-d49965d5-a91b-4b40-996d-bff3e535e582
2N/A * path: /export/home
2N/A * 1:
2N/A * name: exp
2N/A * path: /export/home
2N/A * desc: comment
2N/A * smb:
2N/A * rw: .CIFSDEVDC
2N/A * abe: true
2N/A * csc: manual
2N/A * smb:
2N/A * none: *
2N/A *
2N/A * Format of libshare v2 nvlist
2N/A * -----------------------------
2N/A *
2N/A * The above nvlist is converted in to libshare v2 nvlist by merging the
2N/A * properties of groups and share into nvlist for libshare2.
2N/A *
2N/A * exp:
2N/A * name: exp
2N/A * path: /export/home
2N/A * desc: comment
2N/A * smb:
2N/A * none: *
2N/A * rw: .CIFSDEVDC
2N/A * abe: true
2N/A * csc: manual
2N/A *
2N/A * The above nvlist configuration is written to persistent repository defined
2N/A * by libshare v2.
2N/A */
2N/A
2N/A#include "libshare.h"
2N/A#include "libshare_impl.h"
2N/A#include <string.h>
2N/A#include <ctype.h>
2N/A#include <errno.h>
2N/A#include <uuid/uuid.h>
2N/A#include <sys/param.h>
2N/A#include <signal.h>
2N/A#include <syslog.h>
2N/A#include <sys/varargs.h>
2N/A#include <sys/time.h>
2N/A#include <libintl.h>
2N/A#include <strings.h>
2N/A#include <libscf.h>
2N/A
2N/Assize_t scf_max_name_len;
2N/A
2N/A#define SCH_STATE_UNINIT 0
2N/A#define SCH_STATE_INITIALIZING 1
2N/A#define SCH_STATE_INIT 2
2N/A
2N/A/*
2N/A * Shares are held in a property group with name of the form
2N/A * S-<GUID>. The total length of the name is 38 characters.
2N/A */
2N/A#define SA_SHARE_PG_PREFIX "S-"
2N/A#define SA_SHARE_PG_PREFIXLEN 2
2N/A#define SA_SHARE_PG_LEN 38
2N/A#define SA_MAX_NAME_LEN 100
2N/A
2N/A/*
2N/A * service instance related defines
2N/A */
2N/A#define SA_GROUP_SVC_NAME "network/shares/group"
2N/A
2N/Atypedef struct scfutilhandle {
2N/A scf_handle_t *handle;
2N/A int scf_state;
2N/A scf_service_t *service;
2N/A scf_scope_t *scope;
2N/A scf_transaction_t *trans;
2N/A scf_transaction_entry_t *entry;
2N/A scf_propertygroup_t *pg;
2N/A scf_instance_t *instance;
2N/A} scfutilhandle_t;
2N/A
2N/A/*
2N/A * The SMF facility uses some properties that must exist. We want to
2N/A * skip over these when processing protocol options.
2N/A */
2N/Astatic char *skip_props[] = {
2N/A "modify_authorization",
2N/A "action_authorization",
2N/A "value_authorization",
2N/A NULL
2N/A};
2N/A
2N/Astatic void sa_upgrade_error(int, const char *, ...);
2N/A
2N/A/*
2N/A * sa_upgrade_scf_fini
2N/A *
2N/A * Must be called when done. Called with the handle allocated in
2N/A * sa_upgrade_scf_init(), it cleans up the state and frees any SCF resources
2N/A * still in use.
2N/A */
2N/Astatic void
2N/Asa_upgrade_scf_fini(scfutilhandle_t *handle)
2N/A{
2N/A int unbind = 0;
2N/A
2N/A if (handle != NULL) {
2N/A if (handle->scope != NULL) {
2N/A unbind = 1;
2N/A scf_scope_destroy(handle->scope);
2N/A }
2N/A if (handle->instance != NULL)
2N/A scf_instance_destroy(handle->instance);
2N/A if (handle->service != NULL)
2N/A scf_service_destroy(handle->service);
2N/A if (handle->pg != NULL)
2N/A scf_pg_destroy(handle->pg);
2N/A if (handle->handle != NULL) {
2N/A handle->scf_state = SCH_STATE_UNINIT;
2N/A if (unbind)
2N/A (void) scf_handle_unbind(handle->handle);
2N/A scf_handle_destroy(handle->handle);
2N/A }
2N/A free(handle);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_scf_init
2N/A *
2N/A * Must be called before using any of the SCF functions. It initializes and
2N/A * returns handle to SCF database.
2N/A */
2N/Astatic scfutilhandle_t *
2N/Asa_upgrade_scf_init(void)
2N/A{
2N/A scfutilhandle_t *handle;
2N/A
2N/A scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
2N/A if (scf_max_name_len <= 0)
2N/A scf_max_name_len = SA_MAX_NAME_LEN + 1;
2N/A
2N/A handle = calloc(1, sizeof (scfutilhandle_t));
2N/A if (handle == NULL)
2N/A return (handle);
2N/A
2N/A handle->scf_state = SCH_STATE_INITIALIZING;
2N/A handle->handle = scf_handle_create(SCF_VERSION);
2N/A if (handle->handle == NULL) {
2N/A free(handle);
2N/A handle = NULL;
2N/A sa_upgrade_error(SA_SCF_ERROR,
2N/A "libshare could not access SMF repository: %s",
2N/A scf_strerror(scf_error()));
2N/A return (handle);
2N/A }
2N/A if (scf_handle_bind(handle->handle) != 0)
2N/A goto err;
2N/A
2N/A handle->scope = scf_scope_create(handle->handle);
2N/A handle->service = scf_service_create(handle->handle);
2N/A handle->pg = scf_pg_create(handle->handle);
2N/A
2N/A handle->instance = scf_instance_create(handle->handle);
2N/A if (handle->scope == NULL || handle->service == NULL ||
2N/A handle->pg == NULL || handle->instance == NULL)
2N/A goto err;
2N/A if (scf_handle_get_scope(handle->handle,
2N/A SCF_SCOPE_LOCAL, handle->scope) != 0)
2N/A goto err;
2N/A if (scf_scope_get_service(handle->scope,
2N/A SA_GROUP_SVC_NAME, handle->service) != 0)
2N/A goto err;
2N/A
2N/A handle->scf_state = SCH_STATE_INIT;
2N/A
2N/A return (handle);
2N/A
2N/Aerr:
2N/A (void) sa_upgrade_scf_fini(handle);
2N/A sa_upgrade_error(SA_SCF_ERROR,
2N/A "libshare SMF initialization problem: %s",
2N/A scf_strerror(scf_error()));
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_get_scf_limit
2N/A *
2N/A * Since we use scf_limit a lot and do the same check and return the
2N/A * same value if it fails, implement as a function for code
2N/A * simplification. Basically, if name isn't found, return MAXPATHLEN
2N/A * (1024) so we have a reasonable default buffer size.
2N/A */
2N/Astatic ssize_t
2N/Asa_upgrade_get_scf_limit(uint32_t name)
2N/A{
2N/A ssize_t vallen;
2N/A
2N/A vallen = scf_limit(name);
2N/A if (vallen == (ssize_t)-1)
2N/A vallen = MAXPATHLEN;
2N/A return (vallen);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_skip_property
2N/A *
2N/A * Internal function to check to see if a property is an SMF magic
2N/A * property that needs to be skipped.
2N/A */
2N/Astatic int
2N/Asa_upgrade_skip_property(char *name)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; skip_props[i] != NULL; i++)
2N/A if (strcmp(name, skip_props[i]) == 0)
2N/A return (1);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_dump_list
2N/A *
2N/A * Debug routine to dump nvlist. Called from sa_upgrade_dump method.
2N/A */
2N/Astatic void
2N/Asa_upgrade_dump_list(nvlist_t *list, int ident, boolean_t is_log_smf)
2N/A{
2N/A nvlist_t *nvlist_value;
2N/A nvpair_t *nvp;
2N/A char *attrname, *str;
2N/A
2N/A nvp = nvlist_next_nvpair(list, NULL);
2N/A while (nvp != NULL) {
2N/A attrname = nvpair_name(nvp);
2N/A switch (nvpair_type(nvp)) {
2N/A case DATA_TYPE_STRING:
2N/A (void) nvpair_value_string(nvp, &str);
2N/A salog_debug(0, "%*s%s: %s", ident, "", attrname, str);
2N/A if (is_log_smf)
2N/A (void) fprintf(stderr, "%*s%s: %s\n", ident, "",
2N/A attrname, str);
2N/A break;
2N/A
2N/A case DATA_TYPE_NVLIST:
2N/A (void) nvpair_value_nvlist(nvp, &nvlist_value);
2N/A salog_debug(0, "%*s%s:", ident, "", nvpair_name(nvp));
2N/A if (is_log_smf)
2N/A (void) fprintf(stderr, "%*s%s:\n", ident, "",
2N/A nvpair_name(nvp));
2N/A sa_upgrade_dump_list(nvlist_value,
2N/A ident + 4, is_log_smf);
2N/A break;
2N/A
2N/A default:
2N/A salog_debug(0, "%s: UNSUPPORTED TYPE\n", attrname);
2N/A if (is_log_smf)
2N/A (void) fprintf(stderr, "%s: UNSUPPORTED TYPE\n",
2N/A attrname);
2N/A break;
2N/A }
2N/A nvp = nvlist_next_nvpair(list, nvp);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_dump
2N/A *
2N/A * Debug routine to dump nvlist. Optionally, an header can be provided before
2N/A * dumping the list. If is_log_smb is set to true, the output is logged to SMF
2N/A * service logs.
2N/A */
2N/Astatic void
2N/Asa_upgrade_dump(nvlist_t *list, boolean_t is_log_smf, char *title)
2N/A{
2N/A if (title != NULL) {
2N/A salog_debug(0, "%s", title);
2N/A if (is_log_smf)
2N/A (void) fprintf(stderr, "%s\n", title);
2N/A }
2N/A
2N/A sa_upgrade_dump_list(list, 2, is_log_smf);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_get_nvlist
2N/A *
2N/A * Get nvlist associated with the passed "name" parameter.
2N/A */
2N/Astatic nvlist_t *
2N/Asa_upgrade_get_nvlist(nvlist_t *list, char *name)
2N/A{
2N/A nvlist_t *rlist = NULL;
2N/A
2N/A if ((list == NULL) || (name == NULL))
2N/A return (NULL);
2N/A
2N/A if (nvlist_lookup_nvlist(list, name, &rlist) != 0)
2N/A return (NULL);
2N/A return (rlist);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_map_nvlist_errcodes
2N/A *
2N/A * This routine maps nvlist API error codes to libshare v2 error codes.
2N/A */
2N/Astatic int
2N/Asa_upgrade_map_nvlist_errcodes(int errcode)
2N/A{
2N/A int sa_errcode;
2N/A
2N/A switch (errcode) {
2N/A case 0:
2N/A sa_errcode = SA_OK;
2N/A break;
2N/A case ENOMEM:
2N/A sa_errcode = SA_NO_MEMORY;
2N/A break;
2N/A case EINVAL:
2N/A sa_errcode = SA_INVALID_PROP;
2N/A break;
2N/A default:
2N/A sa_errcode = SA_INTERNAL_ERR;
2N/A }
2N/A return (sa_errcode);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_nvlist_merge
2N/A *
2N/A * This method provides a wrapper around nvlist_merge API and returns
2N/A * libshare v2 error codes.
2N/A */
2N/Astatic int
2N/Asa_upgrade_nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
2N/A{
2N/A int ret;
2N/A
2N/A ret = nvlist_merge(dst, nvl, flag);
2N/A
2N/A return (sa_upgrade_map_nvlist_errcodes(ret));
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_add_nvlist
2N/A *
2N/A * This method provides a wrapper around nvlist_add_nvlist API and returns
2N/A * libshare v2 error codes.
2N/A */
2N/Astatic int
2N/Asa_upgrade_add_nvlist(nvlist_t *list, char *prop, nvlist_t *nlist)
2N/A{
2N/A int ret;
2N/A
2N/A ret = nvlist_add_nvlist(list, prop, nlist);
2N/A
2N/A return (sa_upgrade_map_nvlist_errcodes(ret));
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_extract_resource
2N/A *
2N/A * Extract a resource node from the share node. The resource node is
2N/A * stored in "valuestr" whose format is,
2N/A * "<id1>:<name1>:<description1>" "<id2>:<name2>:<description2>"
2N/A *
2N/A * For example:
2N/A * S-{uuid}/resource astring "1:exp:" "2:exp1:test-descrip"
2N/A */
2N/Astatic int
2N/Asa_upgrade_extract_resource(nvlist_t *share, char *path, char *valuestr)
2N/A{
2N/A char *idx;
2N/A char *name;
2N/A char *description = NULL;
2N/A nvlist_t *resource = NULL;
2N/A int ret = SA_OK;
2N/A
2N/A if ((path == NULL) || (valuestr == NULL))
2N/A return (SA_INVALID_PROP);
2N/A
2N/A idx = valuestr;
2N/A name = strchr(valuestr, ':');
2N/A if (name == NULL) {
2N/A idx = "0";
2N/A name = valuestr;
2N/A } else {
2N/A *name++ = '\0';
2N/A description = strchr(name, ':');
2N/A if (description != NULL)
2N/A *description++ = '\0';
2N/A }
2N/A
2N/A resource = sa_share_alloc(name, path);
2N/A if (resource == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A } else {
2N/A if (description != NULL && strlen(description) > 0)
2N/A ret = sa_share_set_prop(resource, "desc", description);
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(share, idx,
2N/A resource);
2N/A sa_share_free(resource);
2N/A }
2N/A
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret,
2N/A "error parsing resource for %s", path);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_extract_share_prop
2N/A *
2N/A * Extract share properties from the SMF property group.
2N/A */
2N/Astatic int
2N/Asa_upgrade_extract_share_prop(nvlist_t *group, scfutilhandle_t *handle,
2N/A scf_propertygroup_t *pg, char *id)
2N/A{
2N/A scf_iter_t *iter = NULL;
2N/A scf_property_t *prop = NULL;
2N/A scf_value_t *value = NULL;
2N/A ssize_t vallen;
2N/A char *name = NULL;
2N/A char *valuestr = NULL;
2N/A char *sectype = NULL;
2N/A char *proto;
2N/A int ret = SA_OK;
2N/A nvlist_t *node, *pnode, *share, *resource;
2N/A nvlist_t *prot = NULL;
2N/A nvlist_t *sec = NULL;
2N/A boolean_t is_sec = B_FALSE;
2N/A boolean_t is_prot = B_FALSE;
2N/A
2N/A vallen = strlen(id);
2N/A if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN)
2N/A return (SA_OK);
2N/A
2N/A if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
2N/A proto = strchr(id, '_');
2N/A if (proto == NULL)
2N/A return (SA_OK);
2N/A *proto++ = '\0';
2N/A if (*proto == '\0')
2N/A return (SA_OK);
2N/A sectype = strchr(proto, '_');
2N/A if (sectype != NULL)
2N/A *sectype++ = '\0';
2N/A }
2N/A
2N/A share = sa_upgrade_get_nvlist(group, id);
2N/A if (share == NULL)
2N/A return (SA_INVALID_SHARE);
2N/A node = share;
2N/A
2N/A if (sectype != NULL) {
2N/A /*
2N/A * If sectype[0] is a digit, then it is an index into
2N/A * the resource names. We need to find a resource
2N/A * record and then get the properties into an
2N/A * optionset. The optionset becomes the "node" and the
2N/A * rest is hung off of the share.
2N/A */
2N/A if (isdigit((int)*sectype)) {
2N/A resource = sa_upgrade_get_nvlist(share, sectype);
2N/A if (resource == NULL) {
2N/A ret = SA_INVALID_PROP;
2N/A goto out;
2N/A }
2N/A node = resource;
2N/A } else {
2N/A sec = sa_share_alloc(NULL, NULL);
2N/A if (sec == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A is_sec = B_TRUE;
2N/A }
2N/A }
2N/A
2N/A if ((prot = sa_upgrade_get_nvlist(node, proto)) == NULL) {
2N/A prot = sa_share_alloc(NULL, NULL);
2N/A if (prot == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A is_prot = B_TRUE;
2N/A }
2N/A pnode = (is_sec) ? sec : prot;
2N/A
2N/A vallen = sa_upgrade_get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2N/A iter = scf_iter_create(handle->handle);
2N/A value = scf_value_create(handle->handle);
2N/A prop = scf_property_create(handle->handle);
2N/A name = malloc(scf_max_name_len);
2N/A valuestr = malloc(vallen);
2N/A if (iter == NULL || value == NULL || prop == NULL ||
2N/A name == NULL || valuestr == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A if (scf_iter_pg_properties(iter, pg) == 0) {
2N/A while (scf_iter_next_property(iter, prop) > 0) {
2N/A ret = SA_SCF_ERROR;
2N/A if (scf_property_get_name(prop, name,
2N/A scf_max_name_len) > 0) {
2N/A if (scf_property_get_value(prop, value) == 0) {
2N/A if (scf_value_get_astring(value,
2N/A valuestr, vallen) >= 0)
2N/A ret = sa_share_set_prop(pnode,
2N/A name, valuestr);
2N/A }
2N/A }
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A } else {
2N/A ret = SA_SCF_ERROR;
2N/A }
2N/A
2N/A if ((ret == SA_OK) && (proto != NULL)) {
2N/A if (is_sec)
2N/A ret = sa_upgrade_add_nvlist(prot, sectype, sec);
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(node, proto, prot);
2N/A }
2N/Aout:
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret,
2N/A "error parsing properties for share id %s.", id);
2N/A if (is_prot && (prot != NULL))
2N/A sa_share_free(prot);
2N/A if (is_sec && (sec != NULL))
2N/A sa_share_free(sec);
2N/A if (iter != NULL)
2N/A scf_iter_destroy(iter);
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A if (prop != NULL)
2N/A scf_property_destroy(prop);
2N/A if (name != NULL)
2N/A free(name);
2N/A if (valuestr != NULL)
2N/A free(valuestr);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_extract_share
2N/A *
2N/A * Extract the share definition from the share property group.
2N/A */
2N/Astatic int
2N/Asa_upgrade_extract_share(nvlist_t *group, scfutilhandle_t *handle,
2N/A scf_propertygroup_t *pg, char *id)
2N/A{
2N/A scf_iter_t *iter, *viter;
2N/A scf_property_t *prop;
2N/A scf_value_t *value;
2N/A ssize_t vallen;
2N/A char *name, *valuestr, *sh_name;
2N/A int ret = SA_OK;
2N/A boolean_t have_path = B_FALSE;
2N/A boolean_t have_resource = B_FALSE;
2N/A char path[MAXNAMELEN];
2N/A uuid_t uuid;
2N/A nvlist_t *share;
2N/A
2N/A vallen = strlen(id);
2N/A if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
2N/A if ((strncmp(id, SA_SHARE_PG_PREFIX,
2N/A SA_SHARE_PG_PREFIXLEN) != 0) ||
2N/A (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0))
2N/A return (SA_INVALID_UID);
2N/A } else {
2N/A return (SA_OK);
2N/A }
2N/A
2N/A vallen = sa_upgrade_get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2N/A iter = scf_iter_create(handle->handle);
2N/A value = scf_value_create(handle->handle);
2N/A prop = scf_property_create(handle->handle);
2N/A name = malloc(scf_max_name_len);
2N/A valuestr = malloc(vallen);
2N/A if (iter == NULL || value == NULL || prop == NULL ||
2N/A name == NULL || valuestr == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A if (scf_iter_pg_properties(iter, pg) != 0) {
2N/A ret = SA_SCF_ERROR;
2N/A goto out;
2N/A }
2N/A
2N/A share = sa_share_alloc(NULL, NULL);
2N/A if (share == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A ret = sa_share_set_prop(share, "id", id);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(share);
2N/A goto out;
2N/A }
2N/A
2N/A while (scf_iter_next_property(iter, prop) > 0) {
2N/A ret = SA_SCF_ERROR;
2N/A if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
2N/A if ((scf_property_get_value(prop, value) == 0) &&
2N/A (scf_value_get_astring(value,
2N/A valuestr, vallen) >= 0))
2N/A ret = SA_OK;
2N/A else if (strcmp(name, "resource") == 0)
2N/A ret = SA_OK;
2N/A }
2N/A if (ret != SA_OK)
2N/A break;
2N/A
2N/A if (strcmp(name, "path") == 0) {
2N/A have_path = B_TRUE;
2N/A (void) strlcpy(path, valuestr, MAXNAMELEN);
2N/A ret = sa_share_set_prop(share, "path", valuestr);
2N/A } else if (strcmp(name, "description") == 0) {
2N/A ret = sa_share_set_prop(share, "desc", valuestr);
2N/A } else if (strcmp(name, "resource") == 0) {
2N/A viter = scf_iter_create(handle->handle);
2N/A have_resource = B_TRUE;
2N/A if (viter != NULL && have_path &&
2N/A scf_iter_property_values(viter, prop) == 0) {
2N/A while (scf_iter_next_value(viter, value) > 0) {
2N/A if (scf_value_get_ustring(value,
2N/A valuestr, vallen) >= 0)
2N/A ret =
2N/A sa_upgrade_extract_resource(
2N/A share, path, valuestr);
2N/A else if (scf_value_get_astring(value,
2N/A valuestr, vallen) >= 0)
2N/A ret =
2N/A sa_upgrade_extract_resource(
2N/A share, path, valuestr);
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A scf_iter_destroy(viter);
2N/A }
2N/A }
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Some nfs shares do not have resource names. The resource names
2N/A * for these shares are made up using the share path.
2N/A */
2N/A if ((ret == SA_OK) && have_path && !have_resource) {
2N/A sh_name = strdup(path);
2N/A if (sh_name == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A sa_path_to_shr_name(sh_name);
2N/A ret = sa_upgrade_extract_resource(share, path, sh_name);
2N/A free(sh_name);
2N/A }
2N/A
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(group, id, share);
2N/A sa_share_free(share);
2N/Aout:
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret, "error parsing share id %s", id);
2N/A if (name != NULL)
2N/A free(name);
2N/A if (valuestr != NULL)
2N/A free(valuestr);
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A if (iter != NULL)
2N/A scf_iter_destroy(iter);
2N/A if (prop != NULL)
2N/A scf_property_destroy(prop);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_extract_group_prop
2N/A *
2N/A * Extract the name property group and create the specified type of
2N/A * nvlist from the provided group. The nvlist will be of type "optionset"
2N/A * or "security".
2N/A */
2N/Astatic int
2N/Asa_upgrade_extract_group_prop(nvlist_t *group, scfutilhandle_t *handle,
2N/A scf_propertygroup_t *pg, char *proto, char *sectype)
2N/A{
2N/A scf_iter_t *iter;
2N/A scf_property_t *prop;
2N/A scf_value_t *value;
2N/A char *name, *valuestr;
2N/A ssize_t vallen;
2N/A nvlist_t *prot = NULL;
2N/A nvlist_t *sec = NULL;
2N/A nvlist_t *pnode = NULL;
2N/A int ret = SA_OK;
2N/A boolean_t is_sec = B_FALSE;
2N/A boolean_t is_prot = B_FALSE;
2N/A
2N/A if (proto == NULL)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A vallen = sa_upgrade_get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2N/A iter = scf_iter_create(handle->handle);
2N/A value = scf_value_create(handle->handle);
2N/A prop = scf_property_create(handle->handle);
2N/A name = malloc(scf_max_name_len);
2N/A valuestr = malloc(vallen);
2N/A if (iter == NULL || value == NULL || prop == NULL ||
2N/A valuestr == NULL || name == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A if ((prot = sa_upgrade_get_nvlist(group, proto)) == NULL) {
2N/A prot = sa_share_alloc(NULL, NULL);
2N/A if (prot == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A pnode = prot;
2N/A is_prot = B_TRUE;
2N/A } else if (sectype != NULL) {
2N/A sec = sa_share_alloc(NULL, NULL);
2N/A if (sec == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A pnode = sec;
2N/A is_sec = B_TRUE;
2N/A }
2N/A
2N/A if (scf_iter_pg_properties(iter, pg) == 0) {
2N/A while (scf_iter_next_property(iter, prop) > 0) {
2N/A ret = SA_SCF_ERROR;
2N/A if (scf_property_get_name(prop, name,
2N/A scf_max_name_len) > 0) {
2N/A if (sa_upgrade_skip_property(name))
2N/A continue;
2N/A
2N/A if (scf_property_get_value(prop, value) == 0) {
2N/A if (scf_value_get_astring(value,
2N/A valuestr, vallen) >= 0)
2N/A ret = sa_share_set_prop(pnode,
2N/A name, valuestr);
2N/A }
2N/A }
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A } else {
2N/A ret = SA_SCF_ERROR;
2N/A }
2N/A
2N/A if ((ret == SA_OK) && (proto != NULL)) {
2N/A if (sectype != NULL)
2N/A ret = sa_upgrade_add_nvlist(prot, sectype, sec);
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(group, proto, prot);
2N/A }
2N/Aout:
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret,
2N/A "error while parsing group properties.");
2N/A if (is_prot && (prot != NULL))
2N/A sa_share_free(prot);
2N/A if (is_sec && (sec != NULL))
2N/A sa_share_free(sec);
2N/A if (value != NULL)
2N/A scf_value_destroy(value);
2N/A if (iter != NULL)
2N/A scf_iter_destroy(iter);
2N/A if (prop != NULL)
2N/A scf_property_destroy(prop);
2N/A if (name != NULL)
2N/A free(name);
2N/A if (valuestr != NULL)
2N/A free(valuestr);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_extract_group
2N/A *
2N/A * Get the config info for the instance of a group and create an
2N/A * nvlist from it.
2N/A */
2N/Astatic int
2N/Asa_upgrade_extract_group(nvlist_t *glist, scfutilhandle_t *handle,
2N/A scf_instance_t *instance)
2N/A{
2N/A scf_iter_t *iter;
2N/A char *proto, *sectype, *buff;
2N/A boolean_t have_shares = B_FALSE;
2N/A boolean_t have_proto = B_FALSE;
2N/A int ret = SA_OK;
2N/A int err;
2N/A char gname[MAXNAMELEN];
2N/A nvlist_t *group;
2N/A
2N/A buff = malloc(scf_max_name_len);
2N/A if (buff == NULL)
2N/A return (SA_NO_MEMORY);
2N/A
2N/A iter = scf_iter_create(handle->handle);
2N/A if (iter == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
2N/A if (scf_iter_instance_pgs(iter, instance) != 0) {
2N/A ret = SA_SCF_ERROR;
2N/A goto out;
2N/A }
2N/A
2N/A group = sa_share_alloc(NULL, NULL);
2N/A if (group == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A ret = sa_share_set_prop(group, "gname", buff);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(group);
2N/A goto out;
2N/A }
2N/A (void) strlcpy(gname, buff, MAXNAMELEN);
2N/A
2N/A /*
2N/A * Iterate through all the property groups. Property groups
2N/A * starting with "optionset" prefixes are for groups. Property
2N/A * groups starting with "S-" prefix are for shares and
2N/A * resources.
2N/A */
2N/A while (scf_iter_next_pg(iter, handle->pg) > 0) {
2N/A err = scf_pg_get_name(handle->pg, buff,
2N/A scf_max_name_len);
2N/A if (err <= 0)
2N/A continue;
2N/A
2N/A if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
2N/A ret = sa_upgrade_extract_share(group, handle,
2N/A handle->pg, buff);
2N/A have_shares = B_TRUE;
2N/A } else if (strncmp(buff, "optionset", 9) == 0) {
2N/A sectype = proto = NULL;
2N/A proto = strchr(buff, '_');
2N/A if (proto != NULL) {
2N/A *proto++ = '\0';
2N/A have_proto = B_TRUE;
2N/A sectype = strchr(proto, '_');
2N/A if (sectype != NULL)
2N/A *sectype++ = '\0';
2N/A } else if (strlen(buff) > 9) {
2N/A continue;
2N/A }
2N/A
2N/A ret = sa_upgrade_extract_group_prop(group,
2N/A handle, handle->pg, proto, sectype);
2N/A }
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * A share group in a libshare configuration must have a
2N/A * protocol specified. If we cannot get a group protocol,
2N/A * mark it as an error. If no share and protocol is defined
2N/A * for a group, then just delete that group.
2N/A */
2N/A if (!have_proto) {
2N/A if (have_shares) {
2N/A ret = SA_NO_SHARE_PROTO;
2N/A sa_upgrade_dump(group, B_TRUE,
2N/A "GROUP CONFIGURATION");
2N/A } else {
2N/A sa_share_free(group);
2N/A ret = SA_OK;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Do a second pass to get share/resource properties. This is
2N/A * needed as property groups are not sorted in SMF manifest.
2N/A */
2N/A if ((ret == SA_OK) && have_shares &&
2N/A scf_iter_instance_pgs(iter, instance) == 0) {
2N/A while (scf_iter_next_pg(iter, handle->pg) > 0) {
2N/A err = scf_pg_get_name(handle->pg, buff,
2N/A scf_max_name_len);
2N/A if (err <= 0)
2N/A continue;
2N/A
2N/A if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
2N/A ret = sa_upgrade_extract_share_prop(
2N/A group, handle, handle->pg, buff);
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(glist, gname, group);
2N/A sa_share_free(group);
2N/A }
2N/Aout:
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret, "error parsing group %s.", gname);
2N/A if (iter != NULL)
2N/A scf_iter_destroy(iter);
2N/A if (buff != NULL)
2N/A free(buff);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_instance_is_enabled
2N/A *
2N/A * Returns B_TRUE if SMF group instance is in online or offline state.
2N/A * The offline state is required as the start method of the SMF manifest
2N/A * will call the upgrade function.
2N/A */
2N/Astatic boolean_t
2N/Asa_upgrade_instance_is_enabled(scf_instance_t *instance)
2N/A{
2N/A char *state, *fmri;
2N/A int fmri_len, ret;
2N/A
2N/A fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2N/A fmri = malloc(fmri_len + 1);
2N/A if (fmri == NULL)
2N/A return (B_FALSE);
2N/A ret = scf_instance_to_fmri(instance, fmri, fmri_len + 1);
2N/A if (ret == -1) {
2N/A free(fmri);
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A state = smf_get_state(fmri);
2N/A free(fmri);
2N/A if (state == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((strcmp(state, "online") == 0) || (strcmp(state, "offline") == 0))
2N/A return (B_TRUE);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_get_config
2N/A *
2N/A * This method gets the upgrade libshare v1 configuration from a SMF group
2N/A * instance (/network/shares/group:*) and return it in nvlist format.
2N/A * It skips the "zfs" group instances.
2N/A */
2N/Astatic int
2N/Asa_upgrade_get_config(scfutilhandle_t *handle, nvlist_t *root, char *gname,
2N/A boolean_t force_upgrade)
2N/A{
2N/A int ret = SA_OK;
2N/A nvlist_t *glist;
2N/A scf_instance_t *instance;
2N/A
2N/A instance = scf_instance_create(handle->handle);
2N/A if (scf_service_get_instance(handle->service, gname,
2N/A instance) != SCF_SUCCESS) {
2N/A ret = SA_SCF_ERROR;
2N/A goto out;
2N/A }
2N/A
2N/A if (!force_upgrade && !sa_upgrade_instance_is_enabled(instance)) {
2N/A ret = SA_SYSTEM_ERR;
2N/A sa_upgrade_error(ret,
2N/A "svc:/network/shares/group:%s is not enabled", gname);
2N/A return (ret);
2N/A }
2N/A
2N/A glist = sa_share_alloc(NULL, NULL);
2N/A if (glist == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A ret = sa_upgrade_extract_group(glist, handle, instance);
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(root, "sharecfg", glist);
2N/A sa_share_free(glist);
2N/A
2N/Aout:
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret,
2N/A "error getting configuration for group %s", gname);
2N/A if (instance != NULL)
2N/A scf_instance_destroy(instance);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_delete_config
2N/A *
2N/A * This method deletes the SMF group instance (/network/shares/group:*),
2N/A * which stores the upgrade libshare v1 configuration.
2N/A */
2N/Astatic int
2N/Asa_upgrade_delete_config(scfutilhandle_t *handle, char *gname,
2N/A boolean_t force_upgrade)
2N/A{
2N/A int ret = SA_OK;
2N/A scf_instance_t *instance;
2N/A
2N/A instance = scf_instance_create(handle->handle);
2N/A if (scf_service_get_instance(handle->service, gname,
2N/A instance) != SCF_SUCCESS) {
2N/A ret = SA_SCF_ERROR;
2N/A goto out;
2N/A }
2N/A
2N/A if (!force_upgrade && !sa_upgrade_instance_is_enabled(instance)) {
2N/A ret = SA_SYSTEM_ERR;
2N/A sa_upgrade_error(ret,
2N/A "svc:/network/shares/group:%s is not enabled", gname);
2N/A return (ret);
2N/A }
2N/A
2N/A ret = scf_instance_delete(instance);
2N/A if (ret != 0)
2N/A ret = SA_SCF_ERROR;
2N/A
2N/Aout:
2N/A if (instance != NULL)
2N/A scf_instance_destroy(instance);
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret, "error deleting group %s", gname);
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_merge_sec
2N/A *
2N/A * This method merges the "security" properties for a group and/or a share
2N/A * with the "security" properties for a resource.
2N/A */
2N/Astatic int
2N/Asa_upgrade_merge_sec(nvlist_t *src_proto, nvlist_t *dest_proto)
2N/A{
2N/A nvlist_t *sec, *dsec, *tmp_sec;
2N/A nvpair_t *nvp;
2N/A char *secname;
2N/A int ret = SA_OK;
2N/A
2N/A sec = dsec = tmp_sec = NULL;
2N/A for (nvp = nvlist_next_nvpair(src_proto, NULL); nvp != NULL;
2N/A nvp = nvlist_next_nvpair(src_proto, nvp)) {
2N/A if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
2N/A continue;
2N/A
2N/A if (nvpair_value_nvlist(nvp, &sec) != 0)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A if ((secname = nvpair_name(nvp)) == NULL)
2N/A return (SA_INVALID_PROP);
2N/A
2N/A tmp_sec = sa_share_alloc(NULL, NULL);
2N/A if (tmp_sec == NULL)
2N/A return (SA_NO_MEMORY);
2N/A ret = sa_upgrade_nvlist_merge(tmp_sec, sec, 0);
2N/A
2N/A if ((ret == SA_OK) &&
2N/A (nvlist_lookup_nvlist(dest_proto, secname, &dsec) == 0)) {
2N/A if ((!sa_prop_empty_list(tmp_sec)) &&
2N/A (!sa_prop_empty_list(dsec))) {
2N/A ret = sa_upgrade_nvlist_merge(tmp_sec,
2N/A dsec, 0);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(tmp_sec);
2N/A break;
2N/A }
2N/A ret = sa_upgrade_nvlist_merge(dsec,
2N/A tmp_sec, 0);
2N/A }
2N/A }
2N/A sa_share_free(tmp_sec);
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret, "error merging security properties.");
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_merge_prot
2N/A *
2N/A * This method merges the "protocol" properties for a group and/or a share
2N/A * with the "protocol" properties for a resource. It also calls the
2N/A * sa_upgrade_merge_sec() method to merge the "security" properties.
2N/A */
2N/Astatic int
2N/Asa_upgrade_merge_prot(nvlist_t *src_nvl, nvlist_t *dest_nvl)
2N/A{
2N/A nvlist_t *proto, *dproto, *tmp_proto;
2N/A nvpair_t *nvp;
2N/A char *protname;
2N/A int ret = SA_OK;
2N/A
2N/A proto = dproto = tmp_proto = NULL;
2N/A for (nvp = nvlist_next_nvpair(src_nvl, NULL); nvp != NULL;
2N/A nvp = nvlist_next_nvpair(src_nvl, nvp)) {
2N/A if ((protname = nvpair_name(nvp)) == NULL)
2N/A return (SA_INVALID_PROP);
2N/A
2N/A if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
2N/A continue;
2N/A
2N/A if (nvpair_value_nvlist(nvp, &proto) != 0)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A if ((strcasecmp(protname, "nfs") == 0) ||
2N/A (strcasecmp(protname, "smb") == 0)) {
2N/A tmp_proto = sa_share_alloc(NULL, NULL);
2N/A if (tmp_proto == NULL)
2N/A return (SA_NO_MEMORY);
2N/A
2N/A ret = sa_upgrade_nvlist_merge(tmp_proto, proto, 0);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(tmp_proto);
2N/A break;
2N/A }
2N/A
2N/A if (nvlist_lookup_nvlist(dest_nvl,
2N/A protname, &dproto) == 0) {
2N/A ret = sa_upgrade_nvlist_merge(tmp_proto,
2N/A dproto, 0);
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_nvlist_merge(dproto,
2N/A tmp_proto, 0);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(tmp_proto);
2N/A break;
2N/A }
2N/A } else {
2N/A dproto = sa_share_alloc(NULL, NULL);
2N/A if (dproto == NULL) {
2N/A sa_share_free(tmp_proto);
2N/A return (SA_NO_MEMORY);
2N/A }
2N/A
2N/A ret = sa_upgrade_nvlist_merge(dproto,
2N/A tmp_proto, 0);
2N/A if (ret == SA_OK)
2N/A ret = sa_upgrade_add_nvlist(dest_nvl,
2N/A protname, dproto);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(tmp_proto);
2N/A sa_share_free(dproto);
2N/A break;
2N/A }
2N/A sa_share_free(dproto);
2N/A }
2N/A sa_share_free(tmp_proto);
2N/A
2N/A if (ret == SA_OK) {
2N/A dproto = NULL;
2N/A if (nvlist_lookup_nvlist(dest_nvl,
2N/A protname, &dproto) != 0) {
2N/A ret = SA_INVALID_PROTO;
2N/A break;
2N/A }
2N/A
2N/A ret = sa_upgrade_merge_sec(proto, dproto);
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret, "error merging protocol properties.");
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_walk_group
2N/A *
2N/A * This method walks a group (and the nested shares and resources) nvlist,
2N/A * and adds the newly created libshare v2 formatted nvlist(s) in "nvl_new"
2N/A */
2N/Astatic int
2N/Asa_upgrade_walk_group(nvlist_t *nvl_new, nvlist_t *group)
2N/A{
2N/A nvpair_t *gnvp, *snvp, *rnvp;
2N/A nvlist_t *share = NULL;
2N/A nvlist_t *resource = NULL;
2N/A char *propname, *rname;
2N/A int ret = SA_OK;
2N/A
2N/A for (gnvp = nvlist_next_nvpair(group, NULL); gnvp != NULL;
2N/A gnvp = nvlist_next_nvpair(group, gnvp)) {
2N/A propname = nvpair_name(gnvp);
2N/A if ((strcasecmp(propname, "nfs") == 0) ||
2N/A (strcasecmp(propname, "smb") == 0) ||
2N/A (nvpair_type(gnvp) != DATA_TYPE_NVLIST))
2N/A continue;
2N/A
2N/A if (nvpair_value_nvlist(gnvp, &share) != 0)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A for (snvp = nvlist_next_nvpair(share, NULL); snvp != NULL;
2N/A snvp = nvlist_next_nvpair(share, snvp)) {
2N/A propname = nvpair_name(snvp);
2N/A if ((strcasecmp(propname, "nfs") == 0) ||
2N/A (strcasecmp(propname, "smb") == 0) ||
2N/A (nvpair_type(snvp) != DATA_TYPE_NVLIST))
2N/A continue;
2N/A
2N/A if (nvpair_value_nvlist(snvp, &resource) != 0)
2N/A return (SA_INVALID_PROP_VAL);
2N/A
2N/A for (rnvp = nvlist_next_nvpair(resource, NULL);
2N/A rnvp != NULL;
2N/A rnvp = nvlist_next_nvpair(resource, rnvp)) {
2N/A ret = sa_upgrade_merge_prot(group, share);
2N/A if (ret != SA_OK)
2N/A break;
2N/A
2N/A ret = sa_upgrade_merge_prot(share, resource);
2N/A if (ret != SA_OK)
2N/A break;
2N/A
2N/A ret = nvlist_lookup_string(resource, "name",
2N/A &rname);
2N/A ret = sa_upgrade_map_nvlist_errcodes(ret);
2N/A if (rname != NULL && (ret == SA_OK))
2N/A ret = sa_upgrade_add_nvlist(nvl_new,
2N/A rname, resource);
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_convert_config
2N/A *
2N/A * Converts libshare v1 configuration into libshare v2 configuration.
2N/A * The nvlist configuration for libshare v1 is stored in the nvl_old param.
2N/A * The converted nvlist configuration for libshare v2 is returned in nvl_new
2N/A * param.
2N/A */
2N/Astatic int
2N/Asa_upgrade_convert_config(nvlist_t *nvl_new, nvlist_t *nvl_old, char *gname)
2N/A{
2N/A nvpair_t *cnvp, *glnvp;
2N/A nvlist_t *glist = NULL;
2N/A nvlist_t *group = NULL;
2N/A int ret = SA_OK;
2N/A
2N/A for (cnvp = nvlist_next_nvpair(nvl_old, NULL); cnvp != NULL;
2N/A cnvp = nvlist_next_nvpair(nvl_old, cnvp)) {
2N/A if (nvpair_type(cnvp) != DATA_TYPE_NVLIST)
2N/A continue;
2N/A
2N/A if (nvpair_value_nvlist(cnvp, &glist) != 0) {
2N/A ret = SA_INVALID_PROP_VAL;
2N/A break;
2N/A }
2N/A
2N/A for (glnvp = nvlist_next_nvpair(glist, NULL); glnvp != NULL;
2N/A glnvp = nvlist_next_nvpair(glist, glnvp)) {
2N/A if (nvpair_type(glnvp) != DATA_TYPE_NVLIST)
2N/A continue;
2N/A
2N/A if (nvpair_value_nvlist(glnvp, &group) != 0) {
2N/A ret = SA_INVALID_PROP_VAL;
2N/A break;
2N/A }
2N/A
2N/A ret = sa_upgrade_walk_group(nvl_new, group);
2N/A if (ret != SA_OK)
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (ret != SA_OK)
2N/A sa_upgrade_error(ret,
2N/A "error converting group %s to libshare v2 format.", gname);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_sharing_set
2N/A *
2N/A * This method sets the sharesmb/sharenfs property to "on". If the filesystem
2N/A * does not support these properties, then SA_NOT_SUPPORTED error is returned.
2N/A */
2N/Astatic int
2N/Asa_upgrade_sharing_set(libshare_handle_t *shdl, nvlist_t *share, char *gname)
2N/A{
2N/A char *path, *mntpnt;
2N/A sa_proto_t p;
2N/A char *optstr = NULL;
2N/A int ret = SA_OK;
2N/A
2N/A path = sa_share_get_path(share);
2N/A mntpnt = malloc(MAXPATHLEN);
2N/A if (mntpnt == NULL) {
2N/A ret = SA_NO_MEMORY;
2N/A sa_upgrade_error(ret,
2N/A "error setting sharesmb property for share "
2N/A " %s in group %s.", sa_share_get_name(share), gname);
2N/A return (ret);
2N/A }
2N/A
2N/A ret = sa_get_mntpnt_for_path(shdl, path, mntpnt, sizeof (mntpnt),
2N/A NULL, NULL, 0, NULL, 0);
2N/A if (ret != SA_OK) {
2N/A free(mntpnt);
2N/A sa_upgrade_error(ret,
2N/A "error getting mountpoint for share %s in group %s.",
2N/A sa_share_get_name(share), gname);
2N/A return (ret);
2N/A }
2N/A
2N/A for (p = sa_proto_first(); p != SA_PROT_NONE; p = sa_proto_next(p)) {
2N/A if (sa_share_get_proto(share, p) == NULL)
2N/A continue;
2N/A
2N/A if (sa_sharing_get_prop(shdl, mntpnt, NULL, p,
2N/A &optstr) == SA_OK && optstr != NULL) {
2N/A /*
2N/A * in order to preserve share properties, only
2N/A * set this if currently set to off.
2N/A */
2N/A if (strcmp(optstr, "off") == 0) {
2N/A ret = sa_sharing_set_prop(shdl, mntpnt, NULL,
2N/A p, "on");
2N/A if ((ret != SA_NOT_SUPPORTED) &&
2N/A (ret != SA_OK)) {
2N/A free(mntpnt);
2N/A sa_upgrade_error(ret,
2N/A "error setting share%s property "
2N/A "for share %s in group %s",
2N/A sa_proto_to_val(p),
2N/A sa_share_get_name(share), gname);
2N/A
2N/A return (ret);
2N/A }
2N/A }
2N/A free(optstr);
2N/A }
2N/A }
2N/A
2N/A free(mntpnt);
2N/A return (SA_OK);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_write_config
2N/A *
2N/A * This method validates the new libshare v2 config and writes shares
2N/A * in the new SMF instance for libshare v2. It also publishes the new share.
2N/A */
2N/Astatic int
2N/Asa_upgrade_write_config(libshare_handle_t *shdl, nvlist_t *new_nvl,
2N/A char *gname)
2N/A{
2N/A nvpair_t *snvp;
2N/A nvlist_t *share = NULL;
2N/A char errbuf[512], *sname;
2N/A int ret = SA_OK;
2N/A boolean_t is_error = B_FALSE;
2N/A
2N/A for (snvp = nvlist_next_nvpair(new_nvl, NULL); snvp != NULL;
2N/A snvp = nvlist_next_nvpair(new_nvl, snvp)) {
2N/A sa_validate_flags_t flags =
2N/A (SA_VALIDATE_ENABLE | SA_VALIDATE_NAME);
2N/A
2N/A ret = nvpair_value_nvlist(snvp, &share);
2N/A if (ret != 0) {
2N/A is_error = B_TRUE;
2N/A ret = SA_INVALID_PROP_VAL;
2N/A sa_upgrade_error(ret,
2N/A "error validating share for group %s", gname);
2N/A continue;
2N/A }
2N/A
2N/A if ((sname = sa_share_get_name(share)) == NULL)
2N/A sname = "";
2N/A ret = sa_share_validate(shdl, share, flags,
2N/A errbuf, sizeof (errbuf));
2N/A
2N/A /*
2N/A * Ignore SA_DUPLICATE_PATH & SA_INVALID_ACCLIST_PROP_VAL
2N/A * errors on upgrade.
2N/A */
2N/A if (ret == SA_DUPLICATE_PATH ||
2N/A ret == SA_INVALID_ACCLIST_PROP_VAL) {
2N/A salog_debug(ret, "%s: %s", sname, errbuf);
2N/A ret = SA_OK;
2N/A }
2N/A
2N/A if (ret != SA_OK) {
2N/A is_error = B_TRUE;
2N/A sa_upgrade_error(ret,
2N/A "error validating share %s for group "
2N/A "%s: %s", sname, gname, errbuf);
2N/A }
2N/A
2N/A if (ret == SA_OK && sa_share_get_mntpnt(share) == NULL) {
2N/A char mntpnt[MAXPATHLEN];
2N/A char *path;
2N/A
2N/A /* add a mountpoint for legacy */
2N/A path = sa_share_get_path(share);
2N/A ret = sa_get_mntpnt_for_path(shdl, path, mntpnt,
2N/A sizeof (mntpnt), NULL, NULL, 0, NULL, 0);
2N/A if (ret == SA_OK)
2N/A ret = sa_share_set_mntpnt(share, mntpnt);
2N/A if (ret != SA_OK) {
2N/A is_error = B_TRUE;
2N/A sa_upgrade_error(ret, "error setting mountpoint"
2N/A "on share %s for group %s",
2N/A sname, gname);
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (is_error)
2N/A return (SA_INTERNAL_ERR);
2N/A
2N/A for (snvp = nvlist_next_nvpair(new_nvl, NULL); snvp != NULL;
2N/A snvp = nvlist_next_nvpair(new_nvl, snvp)) {
2N/A ret = nvpair_value_nvlist(snvp, &share);
2N/A if (ret != 0) {
2N/A is_error = B_TRUE;
2N/A ret = SA_INVALID_PROP_VAL;
2N/A sa_upgrade_error(ret,
2N/A "error writing share for group %s", gname);
2N/A continue;
2N/A }
2N/A
2N/A if ((sname = sa_share_get_name(share)) == NULL)
2N/A sname = "";
2N/A ret = sa_share_write(shdl, share, B_TRUE, B_TRUE);
2N/A if (ret != SA_OK) {
2N/A is_error = B_TRUE;
2N/A sa_upgrade_error(ret,
2N/A "error writing share %s for group %s",
2N/A sname, gname);
2N/A continue;
2N/A }
2N/A
2N/A ret = sa_upgrade_sharing_set(shdl, share, gname);
2N/A if (ret != SA_OK) {
2N/A is_error = B_TRUE;
2N/A sa_upgrade_error(ret,
2N/A "error writing share %s for group %s",
2N/A sname, gname);
2N/A }
2N/A }
2N/A if (is_error)
2N/A return (SA_INTERNAL_ERR);
2N/A
2N/A return (SA_OK);
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_error
2N/A *
2N/A * This method will log the error message to both syslog and SMF log of the
2N/A * associated SMF service.
2N/A */
2N/Astatic void
2N/Asa_upgrade_error(int err, const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A char errbuf[1024];
2N/A
2N/A va_start(ap, fmt);
2N/A (void) vsnprintf(errbuf, sizeof (errbuf), fmt, ap);
2N/A va_end(ap);
2N/A
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "share upgrade: %s: %s"),
2N/A errbuf, sa_strerror(err));
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "share upgrade: %s: %s\n"),
2N/A errbuf, sa_strerror(err));
2N/A
2N/A if (err == SA_SCF_ERROR) {
2N/A syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "share upgrade: %s"),
2N/A scf_strerror(scf_error()));
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "share upgrade: %s\n"), scf_strerror(scf_error()));
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * sa_upgrade_smf_share_group
2N/A *
2N/A * This method upgrades non-zfs shares from libshare v1 format to
2N/A * libshare v2 format. All shares (and resources) in the passed group
2N/A * name are converted. If force_upgrade is B_TRUE, then the state of
2N/A * legacy group service instances will be ignored.
2N/A */
2N/Aint
2N/Asa_upgrade_smf_share_group(libshare_handle_t *shdl, char *gname,
2N/A boolean_t force_upgrade)
2N/A{
2N/A nvlist_t *new_nvl = NULL;
2N/A nvlist_t *old_nvl = NULL;
2N/A scfutilhandle_t *handle;
2N/A int ret = SA_OK;
2N/A boolean_t is_log_smf = !force_upgrade;
2N/A
2N/A handle = sa_upgrade_scf_init();
2N/A if ((gname == NULL) || (handle == NULL))
2N/A return (SA_SCF_ERROR);
2N/A
2N/A if (strcmp(gname, "zfs") == 0) {
2N/A ret = sa_upgrade_delete_config(handle, gname, force_upgrade);
2N/A sa_upgrade_scf_fini(handle);
2N/A return (SA_OK);
2N/A }
2N/A
2N/A old_nvl = sa_share_alloc(NULL, NULL);
2N/A if (old_nvl == NULL) {
2N/A sa_upgrade_scf_fini(handle);
2N/A return (SA_NO_MEMORY);
2N/A }
2N/A
2N/A ret = sa_upgrade_get_config(handle, old_nvl, gname, force_upgrade);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(old_nvl);
2N/A sa_upgrade_scf_fini(handle);
2N/A return (ret);
2N/A }
2N/A sa_upgrade_dump(old_nvl, is_log_smf, "ORIGINAL CONFIGURATION");
2N/A
2N/A new_nvl = sa_share_alloc(NULL, NULL);
2N/A if (new_nvl == NULL) {
2N/A sa_share_free(old_nvl);
2N/A sa_upgrade_scf_fini(handle);
2N/A return (SA_NO_MEMORY);
2N/A }
2N/A
2N/A ret = sa_upgrade_convert_config(new_nvl, old_nvl, gname);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(old_nvl);
2N/A sa_share_free(new_nvl);
2N/A sa_upgrade_scf_fini(handle);
2N/A return (ret);
2N/A }
2N/A sa_upgrade_dump(new_nvl, is_log_smf, "UPGRADED CONFIGURATION");
2N/A sa_share_free(old_nvl);
2N/A
2N/A ret = sa_upgrade_write_config(shdl, new_nvl, gname);
2N/A if (ret != SA_OK) {
2N/A sa_share_free(new_nvl);
2N/A sa_upgrade_scf_fini(handle);
2N/A return (ret);
2N/A }
2N/A sa_share_free(new_nvl);
2N/A
2N/A ret = sa_upgrade_delete_config(handle, gname, force_upgrade);
2N/A sa_upgrade_scf_fini(handle);
2N/A
2N/A return (ret);
2N/A}