/*
* 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
*/
/*
*/
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <libscf.h>
#include <assert.h>
#include <libgen.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <libdevinfo.h>
#include <regex.h>
#include "suri_impl.h"
#include "suri_strings.h"
/*
* Get the state of a service. If we get the state, return ESURI_OK, and return
* ESURI_ERR otherwise.
*/
static suri_err_t
{
char *s;
return (ESURI_ERR);
}
*status = smf_state_from_string(s);
free(s);
return (ESURI_OK);
}
/*
* Return ESURI_OK if the service is enabled and online, or if we were able to
* to put it online temporarily. Return ESURI_ERR otherwise.
*
* Note that libsvc(3LIB) does not offer any synchronous interface to enable a
* service. The functionality is only in svcadm(1M) which is what we use here.
*/
{
char *cmd;
return (ret);
switch (status) {
case SCF_STATE_ONLINE:
return (ESURI_OK);
case SCF_STATE_DISABLED:
if (ret2 == -1)
/* If we got -1, errno is supposed to have been set. */
if (ret2 == -1) {
return (ESURI_ERR);
}
/*
* If the shell did not terminate normally we return an error.
* We do not assume there is any possibility that the service
* could have been put online.
*/
return (ESURI_ERR);
}
/*
* If the shell did not return 0 then something must have
* failed. Again, we do not care what is the state of the
* service now, let's just bail out.
*/
if (WEXITSTATUS(ret2) != 0) {
return (ESURI_ERR);
}
/*
* So, all seems fine up to now but is the service really
* online?
*/
return (ret);
if (status == SCF_STATE_ONLINE)
return (ESURI_OK);
return (ESURI_ERR);
default:
/*
* Not online nor disabled. We will not try to figure out what
* is going on.
*/
svcname);
return (ESURI_ERR);
}
}
/*
* We have to realpath() only the directory since names from /dev are symbolic
* links to the /devices directory managed by devfs(7FS). However, this
* function can be used on existing device paths only anyway.
*
* Return a specific error on failure and ESURI_OK on success.
*
* Note that the function does not make sure the file exists since it only uses
* realpath() on its directory. See suri_getfiletype() which is supposed to be
* used together with this function.
*
* If devpath_in_action is B_TRUE, do not put the device path into the
* description string. This way the caller hints at that the dev path is going
* to be in the action string. We do not want to print messages like the
* following one:
*
*/
{
int n;
/* Caution, dirname(3C) below modifies its input */
if (devpath_in_action) {
} else {
}
return (ESURI_ERR);
}
/* Caution, basename(3C) below modifies its input */
}
else
if (n == -1) {
goto err;
}
goto err;
}
if (devpath_in_action) {
} else {
}
}
err:
return (ret);
}
/*
* Get an existing disk device path (may be in dev or in rdev) and return the
* device name with its slice stripped. The returned pointer points into the
* original string which is modified in this function.
*/
const char *
{
int ret;
/*
* We are guaranteed to get an existing disk device path. If we fail it
* is an internal error.
*/
/* Get rid of the slice part */
/* Skip the "/dev/r?dsk/" prefix */
}
/*
* Enforce the file path is a regular file.
*/
{
/*
* We need to distinguish ENOENT from other errnos so that a consumer
* can decide whether an object needs to be created.
*/
return (ESURI_NOENT);
}
return (ESURI_ERR);
}
return (ESURI_ERR);
}
return (ESURI_OK);
}
/*
* Enforce the file path is a block device. See suri_enforce_real_devpath() on
* description and use of 'devpath_in_action'.
*/
{
/* We only accept devices under /dev */
if (devpath_in_action) {
} else {
}
return (ESURI_ERR);
}
if (devpath_in_action) {
} else {
}
return (ESURI_NOENT);
}
if (devpath_in_action) {
} else {
}
return (ESURI_ERR);
}
if (devpath_in_action) {
} else {
}
return (ESURI_ERR);
}
return (ESURI_OK);
}
/*
* Open the lofi control device. Optionally return lofi major device number.
*/
static suri_err_t
{
SURIGTEXT("Cannot open lofi control device"),
return (ESURI_ERR);
}
SURIGTEXT("Failed to get major device number"),
return (ESURI_ERR);
}
}
return (ESURI_OK);
}
/*
* This might be the first time we have used this minor number. If so, it might
* also be that the /dev links are in the process of being created by devfsadmd
* (or that they will be created "soon"). We cannot return until they are there
* or the consumer of this library might try to use them and not find them.
*
*/
static suri_err_t
{
int cursleep;
/* Check if links already present */
return (ESURI_OK);
/* First use di_devlink_init() */
(void) di_devlink_fini(&hdl);
goto out;
}
/*
* Under normal conditions, di_devlink_init(DI_MAKE_LINK) above will
* only fail if the caller is missing the sys_config privilege. In that
* case, wait for link creation via sysevents.
*/
return (ESURI_OK);
}
/* One last try */
out:
return (ESURI_ERR);
}
return (ESURI_ERR);
}
return (ESURI_OK);
}
/*
* This is for a file URI only (so far). It maps directly
* suri_file->sf_prop_path property to the handle's mapped device.
*/
{
int lfd;
return (ret);
/* li_filename is MAXPATHLEN long */
sizeof (li.li_filename));
if (lookup_only) {
SURIGTEXT("No such lofi mapping exists for file"),
return (ESURI_ERR);
}
/* Not mapped yet, let us map it. */
SURIGTEXT("Cannot create lofi mapping"),
return (ESURI_ERR);
}
/* Wait for the device links to be created to avoid races. */
return (ret);
}
return (ESURI_OK);
}
/*
* number.
*/
static suri_err_t
{
return (ESURI_ERR);
}
return (ESURI_OK);
}
/*
* Reverse look up a lofi device name as set in the handle's mapped device to a
* filename. This is for a file URI only (so far) so we directly fill out
* suri_file->sf_prop_path.
*/
{
int fd;
return (ret);
}
return (ret);
if (lofi_major != dev_major) {
return (ESURI_NOENT);
}
SURIGTEXT("Failed to look up lofi minor device"),
return (ESURI_ERR);
}
return (ESURI_OK);
}
/*
* Remove the connection between a lofi device and a filename serving as a
* backing store. This function is used with a file URI only (so far) so we work
* directly with suri_file->sf_prop_path. Note that we need a filename to
* unmap the lofi device, not a lofi device name.
*/
{
int fd;
return (ret);
/*
* Note that we use a unix path to unmap a lofi device, not the lofi
* device name itself. It is needed to use the file path since libsuri
* can unmap from a parsed state, too.
*/
sizeof (li.li_filename));
/*
* If the mapping was already removed or if the file does not
* exist ioctl() returns ENOENT. As with other unmap functions,
* we return ESURI_NOENT.
*/
SURIGTEXT("No lofi mapping found for object"),
return (ESURI_NOENT);
}
SURIGTEXT("Could not remove lofi mapping because "
"underlying object is busy"),
return (ESURI_BUSY);
}
SURIGTEXT("Failed to remove lofi mapping"),
return (ESURI_ERR);
}
return (ESURI_OK);
}
/*
* Some URI types are experimental and we do not support those by default. Those
* are used for internal testing and debugging. If a specific file exists, we
* enable that support. Also, we enable it on debug builds by default.
*/
{
#ifdef DEBUG
return (B_TRUE);
#else
return (B_TRUE);
else
return (B_FALSE);
#endif
}
/*
* Expand an array of suri handles. Current size includes a terminating NULL.
* Return an increased array with all handles copied to it. Increase the current
* size. Free the old array. If psh is NULL and *current_size 0, create a new
* array.
*
* If we cannot allocate memory to expand the array treat it as a major error
* and destroy the array. That is consistent with other parts of libsuri.
*/
struct suri_handle **
{
sizeof (suri_handle_t *))) == NULL) {
return (NULL);
}
return (tpsh);
}
/*
* Free all handles and then free the array, too.
*/
void
{
int i;
}
/*
* Get a number of handles in the handle array.
*/
int
{
int i = 0;
++i;
return (i);
}
/*
* A compare function for qsort(3C). We sort handles alphabetically based on URI
* strings.
*/
static int
{
}
/*
* Go through a handle array and remove duplicates based on URI string
* comparison. Do it in place. Upon return, the array will contain a continuous
* sequence of sorted unique handles, terminated by NULL.
*/
void
{
int i, j, n;
/* We must have at least one handle. */
n = suri_get_handle_count(psh);
/*
* Index 'i' is used to index non-duplicate handles and it is not
* increased if the next handle to process (ie., psh[j]) is a duplicate
* of psh[i]. Index 'j' is used to go through the whole array handle by
* handle. We start with i=0 and j=1 but the "gap" widens as we hit
* duplicates.
*/
continue;
}
++i;
/* No duplicates so far, no reshuffling needed. */
if (i == j)
continue;
/* Move it over the gap between i and j. */
}
/* psh[i] is the last handle in the array */
}
/*
* Resolve a hostname part of the authority section in the iSCSI URI.
*/
{
int err;
char *c, *s, *s_orig;
/* We can have an IPv6 address. Those are always in square brackets. */
if (s[0] == '[') {
++s;
c = strchr(s, ']');
/* Hostname property was already parsed. */
*c = '\0';
}
SURIGTEXT("Cannot resolve hostname to IP address"),
return (ESURI_ERR);
}
return (ESURI_OK);
}