root/usr/src/lib/cfgadm_plugins/sbd/common/cfga.c
/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <macros.h>
#include <libdevinfo.h>
#define CFGA_PLUGIN_LIB
#include <config_admin.h>
#include "ap.h"

int cfga_version = CFGA_HSL_V2;

/*ARGSUSED*/
cfga_err_t
cfga_change_state(
        cfga_cmd_t cfga_cmd,
        const char *ap_id,
        const char *options,
        struct cfga_confirm *confp,
        struct cfga_msg *msgp,
        char **errstring,
        cfga_flags_t flags)
{
        int cmd;
        const char *name;
        apd_t *a;
        cfga_err_t rc;

        if ((rc = ap_state_cmd(cfga_cmd, &cmd)) != CFGA_OK)
                return (rc);

        rc = CFGA_LIB_ERROR;

        if ((a = apd_alloc(ap_id, flags, errstring, msgp, confp)) == NULL)
                return (rc);

        name = ap_cmd_name(cmd);

        if ((rc = ap_cmd_parse(a, name, options, NULL)) == CFGA_OK)
                rc = ap_cmd_seq(a, cmd);

        apd_free(a);

        return (rc);
}

/*
 * Check if this is a valid -x command.
 */
static int
private_func(const char *function)
{
        char **f;
        static char *
        private_funcs[] = {
                "assign",
                "unassign",
                "poweron",
                "poweroff",
                "passthru",
                "errtest",
                NULL
        };

        for (f = private_funcs; *f != NULL; f++)
                if (strcmp(*f, function) == 0)
                        break;

        return (*f == NULL ? CFGA_INVAL : CFGA_OK);
}

/*ARGSUSED*/
cfga_err_t
cfga_private_func(
        const char *function,
        const char *ap_id,
        const char *options,
        struct cfga_confirm *confp,
        struct cfga_msg *msgp,
        char **errstring,
        cfga_flags_t flags)
{
        int cmd;
        apd_t *a;
        cfga_err_t rc;

        DBG("cfga_private_func(%s)\n", ap_id);

        rc = CFGA_LIB_ERROR;

        if ((a = apd_alloc(ap_id, flags, errstring, msgp, confp)) == NULL)
                return (rc);
        else if ((rc = private_func(function)) != CFGA_OK)  {
                ap_err(a, ERR_CMD_INVAL, function);
                goto done;
        } else if ((rc = ap_cmd_parse(a, function, options, &cmd)) != CFGA_OK)
                goto done;
        else if (cmd == CMD_ERRTEST)
                rc = ap_test_err(a, options);
        else
                rc = ap_cmd_exec(a, cmd);
done:
        apd_free(a);
        return (rc);
}


/*ARGSUSED*/
cfga_err_t
cfga_test(
        const char *ap_id,
        const char *options,
        struct cfga_msg *msgp,
        char **errstring,
        cfga_flags_t flags)
{
        int cmd;
        const char *f;
        apd_t *a;
        cfga_err_t rc;

        DBG("cfga_test(%s)\n", ap_id);

        f = "test";
        rc = CFGA_LIB_ERROR;

        /*
         * A test that is not sequenced by a change
         * state operation should be forced.
         */
        flags |= CFGA_FLAG_FORCE;

        if ((a = apd_alloc(ap_id, flags, errstring, msgp, NULL)) == NULL)
                return (rc);
        else if ((rc = ap_cmd_parse(a, f, options, &cmd)) != CFGA_OK)
                goto done;
        else
                rc = ap_cmd_exec(a, cmd);
done:
        apd_free(a);
        return (rc);
}

/*ARGSUSED*/
cfga_err_t
cfga_list_ext(
        const char *ap_id,
        cfga_list_data_t **ap_id_list,
        int *nlist,
        const char *options,
        const char *listopts,
        char **errstring,
        cfga_flags_t flags)
{
        int i;
        int apcnt;
        const char *f;
        apd_t *a;
        size_t szl, szp;
        cfga_list_data_t *aplist, *ap;
        cfga_err_t rc;

        rc = CFGA_LIB_ERROR;

        aplist = NULL;
        f = ap_cmd_name(CMD_STATUS);

        DBG("cfga_list_ext(%s %x)\n", ap_id, flags);

        if ((a = apd_alloc(ap_id, flags, errstring, NULL, NULL)) == NULL)
                return (rc);
        else if ((rc = ap_cmd_parse(a, f, options, NULL)) != CFGA_OK)
                goto done;

        apcnt = ap_cnt(a);

        DBG("apcnt=%d\n", apcnt);

        if ((aplist = calloc(apcnt, sizeof (*aplist))) == NULL) {
                rc = CFGA_LIB_ERROR;
                ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
                goto done;
        }

        ap = aplist;
        szl = sizeof (ap->ap_log_id);
        szp = sizeof (ap->ap_phys_id);

        /*
         * Initialize the AP specified directly by the caller.
         * The target ID for the 0th element already includes
         * the (potential) dynamic portion. The dynamic portion
         * does need to be appended to the path to form the
         * physical apid for components.
         */
        (void) strncpy(ap->ap_log_id, a->target, szl - 1);
        (void) snprintf(ap->ap_phys_id, szp, "%s%s%s", a->path,
            a->tgt != AP_BOARD ? "::" : "",
            a->tgt != AP_BOARD ? a->cid : "");


        DBG("ap_phys_id=%s ap_log_id=%s\n", ap->ap_phys_id, ap->ap_log_id);

        if (a->tgt == AP_BOARD) {

                ap_init(a, ap++);

                /*
                 * Initialize the components, if any.
                 */
                for (i = 0; i < apcnt - 1; i++, ap++) {
                        char dyn[MAXPATHLEN];

                        ap_cm_id(a, i, dyn, sizeof (dyn));

                        (void) snprintf(ap->ap_log_id, szl, "%s::%s",
                            a->target, dyn);
                        (void) snprintf(ap->ap_phys_id, szp, "%s::%s",
                            a->path, dyn);

                        ap_cm_init(a, ap, i);

                        DBG("ap_phys_id=%s ap_log_id=%s\n",
                            ap->ap_phys_id, ap->ap_log_id);
                }

        } else
                ap_cm_init(a, ap, 0);

        apd_free(a);
        *ap_id_list = aplist;
        *nlist = apcnt;
        return (CFGA_OK);

done:
        s_free(aplist);
        apd_free(a);
        return (rc);
}

/*ARGSUSED*/
cfga_err_t
cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
{
        return (ap_help(msgp, options, flags));
}


/*
 * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
 */