/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* This file converts shares in libshare v1 format to libshare v2 format.
* The configuration of libshare v1 shares is stored in the
* This configuration is read and converted into nvlist format of
* libshare v2. Additionally, libshare v1 has the concept of groups, shares and
* resources. Groups can contain shares and shares can have different resource
* names. Properties can be defined at each of the 3 levels described above.
* The group properties are inherited by shares and the share properties are
* inherited by resources.
*
* We start out by parsing out the SMF configuration of the share into a
* nvlist format. We then merge the group and share properties
* into the newly defined nvlist share for libshare v2.
*
* Example
* -------
*
* Consider a share defined in libshare v1 format. The share belongs to group
* named "smb". This group has "rw=*" property setting. The shared path is
* named with resource name "exp" and has a description of "comment".
* Additionally the resource has "rw=.CIFSDEVDC, abe=true, csc=manual"
* properties.
*
* smb smb=(rw="*")
*
* Format of the share in SMF configuration
* ----------------------------------------
*
* Group names start with "optionset" and share and resource names
* "exp" belongs to the "smb" group.
*
* :
* optionset_smb application
* optionset_smb/rw astring *
* S-d49965d5-a91b-4b40-996d-bff3e535e582 application
* S-d49965d5-a91b-4b40-996d-bff3e535e582/path astring /export/home
* S-d49965d5-a91b-4b40-996d-bff3e535e582/resource astring "1:exp:comment"
* S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1 application
* S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1/rw astring .CIFSDEVDC
* S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1/abe astring true
* S-d49965d5-a91b-4b40-996d-bff3e535e582_smb_1/csc astring manual
* S-d49965d5-a91b-4b40-996d-bff3e535e582_smb application
* S-d49965d5-a91b-4b40-996d-bff3e535e582_smb/none astring *
*
* Format of the nvlist that is created from the share in SMF
* ----------------------------------------------------------
*
* The SMF configuration is parsed into a nvlist. Below is the output of the
* nvlist created by parsing the SMF configuration of the share.
*
* sharecfg:
* smb:
* gname: smb
* smb:
* rw: *
* S-d49965d5-a91b-4b40-996d-bff3e535e582:
* id: S-d49965d5-a91b-4b40-996d-bff3e535e582
* 1:
* name: exp
* desc: comment
* smb:
* rw: .CIFSDEVDC
* abe: true
* csc: manual
* smb:
* none: *
*
* Format of libshare v2 nvlist
* -----------------------------
*
* The above nvlist is converted in to libshare v2 nvlist by merging the
* properties of groups and share into nvlist for libshare2.
*
* exp:
* name: exp
* desc: comment
* smb:
* none: *
* rw: .CIFSDEVDC
* abe: true
* csc: manual
*
* The above nvlist configuration is written to persistent repository defined
* by libshare v2.
*/
#include "libshare.h"
#include "libshare_impl.h"
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <libintl.h>
#include <strings.h>
#include <libscf.h>
#define SCH_STATE_UNINIT 0
/*
* Shares are held in a property group with name of the form
* S-<GUID>. The total length of the name is 38 characters.
*/
/*
* service instance related defines
*/
typedef struct scfutilhandle {
int scf_state;
/*
* The SMF facility uses some properties that must exist. We want to
* skip over these when processing protocol options.
*/
static char *skip_props[] = {
"modify_authorization",
"action_authorization",
"value_authorization",
};
static void sa_upgrade_error(int, const char *, ...);
/*
* sa_upgrade_scf_fini
*
* Must be called when done. Called with the handle allocated in
* sa_upgrade_scf_init(), it cleans up the state and frees any SCF resources
* still in use.
*/
static void
{
int unbind = 0;
unbind = 1;
}
if (unbind)
}
}
}
/*
* sa_upgrade_scf_init
*
* Must be called before using any of the SCF functions. It initializes and
* returns handle to SCF database.
*/
static scfutilhandle_t *
sa_upgrade_scf_init(void)
{
if (scf_max_name_len <= 0)
return (handle);
"libshare could not access SMF repository: %s",
scf_strerror(scf_error()));
return (handle);
}
goto err;
goto err;
goto err;
goto err;
return (handle);
err:
(void) sa_upgrade_scf_fini(handle);
"libshare SMF initialization problem: %s",
scf_strerror(scf_error()));
return (NULL);
}
/*
* sa_upgrade_get_scf_limit
*
* Since we use scf_limit a lot and do the same check and return the
* same value if it fails, implement as a function for code
* simplification. Basically, if name isn't found, return MAXPATHLEN
* (1024) so we have a reasonable default buffer size.
*/
static ssize_t
{
vallen = MAXPATHLEN;
return (vallen);
}
/*
* sa_upgrade_skip_property
*
* Internal function to check to see if a property is an SMF magic
* property that needs to be skipped.
*/
static int
{
int i;
for (i = 0; skip_props[i] != NULL; i++)
return (1);
return (0);
}
/*
* sa_upgrade_dump_list
*
* Debug routine to dump nvlist. Called from sa_upgrade_dump method.
*/
static void
{
switch (nvpair_type(nvp)) {
case DATA_TYPE_STRING:
if (is_log_smf)
break;
case DATA_TYPE_NVLIST:
if (is_log_smf)
nvpair_name(nvp));
ident + 4, is_log_smf);
break;
default:
if (is_log_smf)
attrname);
break;
}
}
}
/*
* sa_upgrade_dump
*
* Debug routine to dump nvlist. Optionally, an header can be provided before
* dumping the list. If is_log_smb is set to true, the output is logged to SMF
* service logs.
*/
static void
{
if (is_log_smf)
}
}
/*
* sa_upgrade_get_nvlist
*
* Get nvlist associated with the passed "name" parameter.
*/
static nvlist_t *
{
return (NULL);
return (NULL);
return (rlist);
}
/*
* sa_upgrade_map_nvlist_errcodes
*
* This routine maps nvlist API error codes to libshare v2 error codes.
*/
static int
{
int sa_errcode;
switch (errcode) {
case 0:
sa_errcode = SA_OK;
break;
case ENOMEM:
break;
case EINVAL:
break;
default:
}
return (sa_errcode);
}
/*
* sa_upgrade_nvlist_merge
*
* This method provides a wrapper around nvlist_merge API and returns
* libshare v2 error codes.
*/
static int
{
int ret;
return (sa_upgrade_map_nvlist_errcodes(ret));
}
/*
* sa_upgrade_add_nvlist
*
* This method provides a wrapper around nvlist_add_nvlist API and returns
* libshare v2 error codes.
*/
static int
{
int ret;
return (sa_upgrade_map_nvlist_errcodes(ret));
}
/*
* sa_upgrade_extract_resource
*
* Extract a resource node from the share node. The resource node is
* stored in "valuestr" whose format is,
* "<id1>:<name1>:<description1>" "<id2>:<name2>:<description2>"
*
* For example:
* S-{uuid}/resource astring "1:exp:" "2:exp1:test-descrip"
*/
static int
{
char *idx;
char *name;
return (SA_INVALID_PROP);
idx = "0";
} else {
*name++ = '\0';
if (description != NULL)
*description++ = '\0';
}
ret = SA_NO_MEMORY;
} else {
resource);
}
"error parsing resource for %s", path);
return (ret);
}
/*
* sa_upgrade_extract_share_prop
*
* Extract share properties from the SMF property group.
*/
static int
{
char *proto;
return (SA_OK);
return (SA_OK);
*proto++ = '\0';
if (*proto == '\0')
return (SA_OK);
*sectype++ = '\0';
}
return (SA_INVALID_SHARE);
/*
* If sectype[0] is a digit, then it is an index into
* the resource names. We need to find a resource
* record and then get the properties into an
* optionset. The optionset becomes the "node" and the
* rest is hung off of the share.
*/
goto out;
}
} else {
ret = SA_NO_MEMORY;
goto out;
}
}
}
ret = SA_NO_MEMORY;
goto out;
}
}
ret = SA_NO_MEMORY;
goto out;
}
ret = SA_SCF_ERROR;
scf_max_name_len) > 0) {
}
}
break;
}
} else {
ret = SA_SCF_ERROR;
}
if (is_sec)
}
out:
"error parsing properties for share id %s.", id);
return (ret);
}
/*
* sa_upgrade_extract_share
*
* Extract the share definition from the share property group.
*/
static int
{
SA_SHARE_PG_PREFIXLEN) != 0) ||
return (SA_INVALID_UID);
} else {
return (SA_OK);
}
ret = SA_NO_MEMORY;
goto out;
}
ret = SA_SCF_ERROR;
goto out;
}
ret = SA_NO_MEMORY;
goto out;
}
goto out;
}
ret = SA_SCF_ERROR;
}
break;
ret =
else if (scf_value_get_astring(value,
ret =
break;
}
}
}
break;
}
/*
* Some nfs shares do not have resource names. The resource names
* for these shares are made up using the share path.
*/
ret = SA_NO_MEMORY;
goto out;
}
}
out:
return (ret);
}
/*
* sa_upgrade_extract_group_prop
*
* Extract the name property group and create the specified type of
* nvlist from the provided group. The nvlist will be of type "optionset"
* or "security".
*/
static int
{
return (SA_INVALID_PROP_VAL);
ret = SA_NO_MEMORY;
goto out;
}
ret = SA_NO_MEMORY;
goto out;
}
ret = SA_NO_MEMORY;
goto out;
}
}
ret = SA_SCF_ERROR;
scf_max_name_len) > 0) {
if (sa_upgrade_skip_property(name))
continue;
}
}
break;
}
} else {
ret = SA_SCF_ERROR;
}
}
out:
"error while parsing group properties.");
return (ret);
}
/*
* sa_upgrade_extract_group
*
* Get the config info for the instance of a group and create an
* nvlist from it.
*/
static int
{
int err;
return (SA_NO_MEMORY);
ret = SA_NO_MEMORY;
goto out;
}
ret = SA_SCF_ERROR;
goto out;
}
ret = SA_NO_MEMORY;
goto out;
}
goto out;
}
/*
* Iterate through all the property groups. Property groups
* starting with "optionset" prefixes are for groups. Property
* groups starting with "S-" prefix are for shares and
* resources.
*/
if (err <= 0)
continue;
if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
*proto++ = '\0';
have_proto = B_TRUE;
*sectype++ = '\0';
continue;
}
}
break;
}
/*
* A share group in a libshare configuration must have a
* protocol specified. If we cannot get a group protocol,
* mark it as an error. If no share and protocol is defined
* for a group, then just delete that group.
*/
if (!have_proto) {
if (have_shares) {
"GROUP CONFIGURATION");
} else {
goto out;
}
}
/*
* needed as property groups are not sorted in SMF manifest.
*/
if (err <= 0)
continue;
if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
break;
}
}
}
}
out:
return (ret);
}
/*
* sa_upgrade_instance_is_enabled
*
* Returns B_TRUE if SMF group instance is in online or offline state.
* The offline state is required as the start method of the SMF manifest
* will call the upgrade function.
*/
static boolean_t
{
return (B_FALSE);
if (ret == -1) {
return (B_FALSE);
}
return (B_FALSE);
return (B_TRUE);
return (B_FALSE);
}
/*
* sa_upgrade_get_config
*
* This method gets the upgrade libshare v1 configuration from a SMF group
* It skips the "zfs" group instances.
*/
static int
{
instance) != SCF_SUCCESS) {
ret = SA_SCF_ERROR;
goto out;
}
ret = SA_SYSTEM_ERR;
return (ret);
}
ret = SA_NO_MEMORY;
goto out;
}
out:
"error getting configuration for group %s", gname);
return (ret);
}
/*
* sa_upgrade_delete_config
*
* which stores the upgrade libshare v1 configuration.
*/
static int
{
instance) != SCF_SUCCESS) {
ret = SA_SCF_ERROR;
goto out;
}
ret = SA_SYSTEM_ERR;
return (ret);
}
if (ret != 0)
ret = SA_SCF_ERROR;
out:
return (ret);
}
/*
* sa_upgrade_merge_sec
*
* with the "security" properties for a resource.
*/
static int
{
char *secname;
continue;
return (SA_INVALID_PROP_VAL);
return (SA_INVALID_PROP);
return (SA_NO_MEMORY);
if ((!sa_prop_empty_list(tmp_sec)) &&
(!sa_prop_empty_list(dsec))) {
dsec, 0);
break;
}
tmp_sec, 0);
}
}
break;
}
return (ret);
}
/*
* sa_upgrade_merge_prot
*
* with the "protocol" properties for a resource. It also calls the
* sa_upgrade_merge_sec() method to merge the "security" properties.
*/
static int
{
char *protname;
return (SA_INVALID_PROP);
continue;
return (SA_INVALID_PROP_VAL);
return (SA_NO_MEMORY);
break;
}
dproto, 0);
tmp_proto, 0);
break;
}
} else {
return (SA_NO_MEMORY);
}
tmp_proto, 0);
break;
}
}
break;
}
break;
}
}
}
return (ret);
}
/*
* sa_upgrade_walk_group
*
* This method walks a group (and the nested shares and resources) nvlist,
* and adds the newly created libshare v2 formatted nvlist(s) in "nvl_new"
*/
static int
{
continue;
return (SA_INVALID_PROP_VAL);
continue;
return (SA_INVALID_PROP_VAL);
break;
break;
&rname);
break;
}
}
}
return (ret);
}
/*
* sa_upgrade_convert_config
*
* Converts libshare v1 configuration into libshare v2 configuration.
* The nvlist configuration for libshare v1 is stored in the nvl_old param.
* The converted nvlist configuration for libshare v2 is returned in nvl_new
* param.
*/
static int
{
continue;
break;
}
continue;
break;
}
break;
}
}
"error converting group %s to libshare v2 format.", gname);
return (ret);
}
/*
* sa_upgrade_sharing_set
*
* does not support these properties, then SA_NOT_SUPPORTED error is returned.
*/
static int
{
sa_proto_t p;
ret = SA_NO_MEMORY;
"error setting sharesmb property for share "
return (ret);
}
"error getting mountpoint for share %s in group %s.",
return (ret);
}
continue;
/*
* in order to preserve share properties, only
* set this if currently set to off.
*/
p, "on");
if ((ret != SA_NOT_SUPPORTED) &&
"error setting share%s property "
"for share %s in group %s",
sa_proto_to_val(p),
return (ret);
}
}
}
}
return (SA_OK);
}
/*
* sa_upgrade_write_config
*
* This method validates the new libshare v2 config and writes shares
* in the new SMF instance for libshare v2. It also publishes the new share.
*/
static int
char *gname)
{
if (ret != 0) {
"error validating share for group %s", gname);
continue;
}
sname = "";
/*
* Ignore SA_DUPLICATE_PATH & SA_INVALID_ACCLIST_PROP_VAL
* errors on upgrade.
*/
if (ret == SA_DUPLICATE_PATH ||
}
"error validating share %s for group "
}
char *path;
/* add a mountpoint for legacy */
"on share %s for group %s",
}
}
}
if (is_error)
return (SA_INTERNAL_ERR);
if (ret != 0) {
"error writing share for group %s", gname);
continue;
}
sname = "";
"error writing share %s for group %s",
continue;
}
"error writing share %s for group %s",
}
}
if (is_error)
return (SA_INTERNAL_ERR);
return (SA_OK);
}
/*
* sa_upgrade_error
*
* This method will log the error message to both syslog and SMF log of the
* associated SMF service.
*/
static void
{
if (err == SA_SCF_ERROR) {
scf_strerror(scf_error()));
}
}
/*
* sa_upgrade_smf_share_group
*
* This method upgrades non-zfs shares from libshare v1 format to
* libshare v2 format. All shares (and resources) in the passed group
* name are converted. If force_upgrade is B_TRUE, then the state of
* legacy group service instances will be ignored.
*/
int
{
return (SA_SCF_ERROR);
return (SA_OK);
}
return (SA_NO_MEMORY);
}
return (ret);
}
return (SA_NO_MEMORY);
}
return (ret);
}
return (ret);
}
return (ret);
}