195efa359SEric Schrock /* 295efa359SEric Schrock * CDDL HEADER START 395efa359SEric Schrock * 495efa359SEric Schrock * The contents of this file are subject to the terms of the 595efa359SEric Schrock * Common Development and Distribution License (the "License"). 695efa359SEric Schrock * You may not use this file except in compliance with the License. 795efa359SEric Schrock * 895efa359SEric Schrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 995efa359SEric Schrock * or http://www.opensolaris.org/os/licensing. 1095efa359SEric Schrock * See the License for the specific language governing permissions 1195efa359SEric Schrock * and limitations under the License. 1295efa359SEric Schrock * 1395efa359SEric Schrock * When distributing Covered Code, include this CDDL HEADER in each 1495efa359SEric Schrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1595efa359SEric Schrock * If applicable, add the following below this CDDL HEADER, with the 1695efa359SEric Schrock * fields enclosed by brackets "[]" replaced with your own identifying 1795efa359SEric Schrock * information: Portions Copyright [yyyy] [name of copyright owner] 1895efa359SEric Schrock * 1995efa359SEric Schrock * CDDL HEADER END 2095efa359SEric Schrock */ 2195efa359SEric Schrock 2295efa359SEric Schrock /* 23*f6e214c7SGavin Maltby * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2495efa359SEric Schrock */ 2595efa359SEric Schrock 2695efa359SEric Schrock /* 2795efa359SEric Schrock * This provides the basic mechanisms (str2nvl and nvl2str) for dealing with 2895efa359SEric Schrock * the service schema. The official version of a svc FMRI has the form: 2995efa359SEric Schrock * 30*f6e214c7SGavin Maltby * svc://[scope@][system-fqn]/service[:instance][@contract-id] 3195efa359SEric Schrock * 3295efa359SEric Schrock * Where 'service' is a slash-delimited list of names. Of these fields, the 3395efa359SEric Schrock * scope, constract-id, and system-fqn are rarely used, leaving the much more 3495efa359SEric Schrock * common form such as: 3595efa359SEric Schrock * 36*f6e214c7SGavin Maltby * svc:///network/ssh:default 3795efa359SEric Schrock * 3895efa359SEric Schrock * Note that the SMF software typically uses a shorthard form, where the 3995efa359SEric Schrock * authority is elided (svc:/network/ssh:default). As this module deals with 4095efa359SEric Schrock * FMA FMRIs, we only support fully specified FMRIs. 4195efa359SEric Schrock * 4295efa359SEric Schrock * This module does not support enumeration, but implements methods for FMRI 4395efa359SEric Schrock * state (present, unusable, service state, and replaced). 4495efa359SEric Schrock */ 4595efa359SEric Schrock 4695efa359SEric Schrock #include <fm/topo_mod.h> 4795efa359SEric Schrock #include <fm/fmd_fmri.h> 4895efa359SEric Schrock #include <sys/fm/protocol.h> 4995efa359SEric Schrock #include <topo_method.h> 5095efa359SEric Schrock #include <topo_subr.h> 51*f6e214c7SGavin Maltby #include <topo_prop.h> 5295efa359SEric Schrock #include <alloca.h> 5395efa359SEric Schrock #include <assert.h> 5495efa359SEric Schrock #include <svc.h> 5595efa359SEric Schrock #include <strings.h> 5695efa359SEric Schrock #include <libscf.h> 5795efa359SEric Schrock 5895efa359SEric Schrock static int svc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 5995efa359SEric Schrock nvlist_t *, nvlist_t **); 6095efa359SEric Schrock static int svc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 6195efa359SEric Schrock nvlist_t *, nvlist_t **); 6295efa359SEric Schrock static int svc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, 6395efa359SEric Schrock nvlist_t *, nvlist_t **); 6495efa359SEric Schrock static int svc_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, 6595efa359SEric Schrock nvlist_t *, nvlist_t **); 6695efa359SEric Schrock static int svc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t, 6795efa359SEric Schrock nvlist_t *, nvlist_t **); 6895efa359SEric Schrock static int svc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, 6995efa359SEric Schrock nvlist_t *, nvlist_t **); 70*f6e214c7SGavin Maltby static int svc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t, 71*f6e214c7SGavin Maltby nvlist_t *, nvlist_t **); 7295efa359SEric Schrock 7395efa359SEric Schrock static const topo_method_t svc_methods[] = { 74*f6e214c7SGavin Maltby { TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC, 75*f6e214c7SGavin Maltby TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL, 76*f6e214c7SGavin Maltby svc_fmri_prop_get }, 7795efa359SEric Schrock { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 7895efa359SEric Schrock TOPO_STABILITY_INTERNAL, svc_fmri_nvl2str }, 7995efa359SEric Schrock { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 8095efa359SEric Schrock TOPO_STABILITY_INTERNAL, svc_fmri_str2nvl }, 8195efa359SEric Schrock { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, 8295efa359SEric Schrock TOPO_STABILITY_INTERNAL, svc_fmri_present }, 8395efa359SEric Schrock { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, 8495efa359SEric Schrock TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, 8595efa359SEric Schrock svc_fmri_replaced }, 8695efa359SEric Schrock { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC, 8795efa359SEric Schrock TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL, 8895efa359SEric Schrock svc_fmri_service_state }, 8995efa359SEric Schrock { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 9095efa359SEric Schrock TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, 9195efa359SEric Schrock svc_fmri_unusable }, 9295efa359SEric Schrock { NULL } 9395efa359SEric Schrock }; 9495efa359SEric Schrock 95*f6e214c7SGavin Maltby static int svc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 96*f6e214c7SGavin Maltby topo_instance_t, void *, void *); 97*f6e214c7SGavin Maltby static void svc_release(topo_mod_t *, tnode_t *); 98*f6e214c7SGavin Maltby 9995efa359SEric Schrock static const topo_modops_t svc_ops = 10095efa359SEric Schrock { svc_enum, svc_release }; 10195efa359SEric Schrock static const topo_modinfo_t svc_info = 10295efa359SEric Schrock { "svc", FM_FMRI_SCHEME_SVC, SVC_VERSION, &svc_ops }; 10395efa359SEric Schrock 10495efa359SEric Schrock static int 10595efa359SEric Schrock svc_error(topo_mod_t *mod) 10695efa359SEric Schrock { 10795efa359SEric Schrock switch (scf_error()) { 10895efa359SEric Schrock case SCF_ERROR_NO_MEMORY: 10995efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 11095efa359SEric Schrock 11195efa359SEric Schrock default: 11295efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 11395efa359SEric Schrock } 11495efa359SEric Schrock } 11595efa359SEric Schrock 1169f342a5aSEric Schrock static scf_handle_t * 1179f342a5aSEric Schrock svc_get_handle(topo_mod_t *mod) 11895efa359SEric Schrock { 1199f342a5aSEric Schrock scf_handle_t *hdl = topo_mod_getspecific(mod); 12095efa359SEric Schrock 1219f342a5aSEric Schrock if (hdl != NULL) 1229f342a5aSEric Schrock return (hdl); 12395efa359SEric Schrock 1249f342a5aSEric Schrock if ((hdl = scf_handle_create(SCF_VERSION)) == NULL) { 1259f342a5aSEric Schrock (void) svc_error(mod); 1269f342a5aSEric Schrock return (NULL); 1279f342a5aSEric Schrock } 12895efa359SEric Schrock 12995efa359SEric Schrock if (scf_handle_bind(hdl) != 0) { 13095efa359SEric Schrock scf_handle_destroy(hdl); 1319f342a5aSEric Schrock (void) svc_error(mod); 1329f342a5aSEric Schrock return (NULL); 13395efa359SEric Schrock } 13495efa359SEric Schrock 1359f342a5aSEric Schrock topo_mod_setspecific(mod, hdl); 1369f342a5aSEric Schrock 1379f342a5aSEric Schrock return (hdl); 1389f342a5aSEric Schrock } 1399f342a5aSEric Schrock 1409f342a5aSEric Schrock int 1419f342a5aSEric Schrock svc_init(topo_mod_t *mod, topo_version_t version) 1429f342a5aSEric Schrock { 143*f6e214c7SGavin Maltby if (getenv("TOPOSVCDEBUG")) 144*f6e214c7SGavin Maltby topo_mod_setdebug(mod); 145*f6e214c7SGavin Maltby 1469f342a5aSEric Schrock if (version != SVC_VERSION) 1479f342a5aSEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 1489f342a5aSEric Schrock 14995efa359SEric Schrock if (topo_mod_register(mod, &svc_info, TOPO_VERSION) != 0) { 15095efa359SEric Schrock topo_mod_dprintf(mod, "failed to register svc_info: " 15195efa359SEric Schrock "%s\n", topo_mod_errmsg(mod)); 15295efa359SEric Schrock return (-1); 15395efa359SEric Schrock } 15495efa359SEric Schrock 15595efa359SEric Schrock return (0); 15695efa359SEric Schrock } 15795efa359SEric Schrock 15895efa359SEric Schrock void 15995efa359SEric Schrock svc_fini(topo_mod_t *mod) 16095efa359SEric Schrock { 16195efa359SEric Schrock scf_handle_t *hdl = topo_mod_getspecific(mod); 16295efa359SEric Schrock 1639f342a5aSEric Schrock if (hdl != NULL) 1649f342a5aSEric Schrock scf_handle_destroy(hdl); 16595efa359SEric Schrock 16695efa359SEric Schrock topo_mod_unregister(mod); 16795efa359SEric Schrock } 16895efa359SEric Schrock 169*f6e214c7SGavin Maltby static tnode_t * 170*f6e214c7SGavin Maltby svc_create_node(topo_mod_t *mod, tnode_t *pnode, char *fmristr) 171*f6e214c7SGavin Maltby { 172*f6e214c7SGavin Maltby nvlist_t *fmri; 173*f6e214c7SGavin Maltby tnode_t *tn; 174*f6e214c7SGavin Maltby char *fixed; 175*f6e214c7SGavin Maltby ssize_t len; 176*f6e214c7SGavin Maltby int i, j, err; 177*f6e214c7SGavin Maltby 178*f6e214c7SGavin Maltby /* 179*f6e214c7SGavin Maltby * the scf_{x}_to_fmri interfaces return short-hand svc-scheme FMRI's 180*f6e214c7SGavin Maltby * that look like: 181*f6e214c7SGavin Maltby * 182*f6e214c7SGavin Maltby * svc:/service[:instance] 183*f6e214c7SGavin Maltby * 184*f6e214c7SGavin Maltby * But all our other code assumes a proper svc-scheme FMRI, so we 185*f6e214c7SGavin Maltby * correct the fmri string before we try to convert it to an nvlist. 186*f6e214c7SGavin Maltby * 187*f6e214c7SGavin Maltby * The short-hand version is kept as the label and can be used when 188*f6e214c7SGavin Maltby * dealing with the SMF libraries and CLI's. 189*f6e214c7SGavin Maltby */ 190*f6e214c7SGavin Maltby len = strlen(fmristr) + 1; 191*f6e214c7SGavin Maltby if ((fixed = topo_mod_zalloc(mod, len + 1)) == NULL) { 192*f6e214c7SGavin Maltby (void) topo_mod_seterrno(mod, EMOD_NOMEM); 193*f6e214c7SGavin Maltby topo_mod_dprintf(mod, "topo_mod_zalloc() failed: %s", 194*f6e214c7SGavin Maltby topo_mod_errmsg(mod)); 195*f6e214c7SGavin Maltby return (NULL); 196*f6e214c7SGavin Maltby } 197*f6e214c7SGavin Maltby for (i = 0, j = 0; i < len; i++) 198*f6e214c7SGavin Maltby if (i == 5) 199*f6e214c7SGavin Maltby fixed[i] = '/'; 200*f6e214c7SGavin Maltby else 201*f6e214c7SGavin Maltby fixed[i] = fmristr[j++]; 202*f6e214c7SGavin Maltby fixed[i] = '\0'; 203*f6e214c7SGavin Maltby 204*f6e214c7SGavin Maltby if (topo_mod_str2nvl(mod, fixed, &fmri) < 0) { 205*f6e214c7SGavin Maltby topo_mod_dprintf(mod, "topo_mod_str2nvl() failed: %s", 206*f6e214c7SGavin Maltby topo_mod_errmsg(mod)); 207*f6e214c7SGavin Maltby topo_mod_free(mod, fixed, len + 1); 208*f6e214c7SGavin Maltby return (NULL); 209*f6e214c7SGavin Maltby } 210*f6e214c7SGavin Maltby topo_mod_free(mod, fixed, len + 1); 211*f6e214c7SGavin Maltby 212*f6e214c7SGavin Maltby if (topo_node_range_create(mod, pnode, fmristr, 0, 0) < 0) { 213*f6e214c7SGavin Maltby topo_mod_dprintf(mod, "topo_node_range_create() failed: %s", 214*f6e214c7SGavin Maltby topo_mod_errmsg(mod)); 215*f6e214c7SGavin Maltby nvlist_free(fmri); 216*f6e214c7SGavin Maltby return (NULL); 217*f6e214c7SGavin Maltby } 218*f6e214c7SGavin Maltby if ((tn = topo_node_bind(mod, pnode, fmristr, 0, fmri)) == NULL) { 219*f6e214c7SGavin Maltby topo_mod_dprintf(mod, "topo_node_bind() failed: %s", 220*f6e214c7SGavin Maltby topo_mod_errmsg(mod)); 221*f6e214c7SGavin Maltby nvlist_free(fmri); 222*f6e214c7SGavin Maltby return (NULL); 223*f6e214c7SGavin Maltby } 224*f6e214c7SGavin Maltby nvlist_free(fmri); 225*f6e214c7SGavin Maltby 226*f6e214c7SGavin Maltby if (topo_node_label_set(tn, fmristr, &err) != 0) { 227*f6e214c7SGavin Maltby topo_mod_dprintf(mod, "failed to set label: %s\n", 228*f6e214c7SGavin Maltby topo_strerror(err)); 229*f6e214c7SGavin Maltby return (NULL); 230*f6e214c7SGavin Maltby } 231*f6e214c7SGavin Maltby (void) topo_method_register(mod, tn, svc_methods); 232*f6e214c7SGavin Maltby 233*f6e214c7SGavin Maltby return (tn); 234*f6e214c7SGavin Maltby } 235*f6e214c7SGavin Maltby 23695efa359SEric Schrock /*ARGSUSED*/ 23795efa359SEric Schrock static int 23895efa359SEric Schrock svc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 23995efa359SEric Schrock topo_instance_t min, topo_instance_t max, void *notused1, void *notused2) 24095efa359SEric Schrock { 241*f6e214c7SGavin Maltby scf_handle_t *hdl; 242*f6e214c7SGavin Maltby scf_scope_t *sc = NULL; 243*f6e214c7SGavin Maltby scf_iter_t *svc_iter = NULL; 244*f6e214c7SGavin Maltby scf_iter_t *inst_iter = NULL; 245*f6e214c7SGavin Maltby scf_service_t *svc = NULL; 246*f6e214c7SGavin Maltby scf_instance_t *inst = NULL; 247*f6e214c7SGavin Maltby int ret = -1; 248*f6e214c7SGavin Maltby char *sfmri, *ifmri; 249*f6e214c7SGavin Maltby ssize_t slen, ilen; 250*f6e214c7SGavin Maltby tnode_t *svc_node; 251*f6e214c7SGavin Maltby 25295efa359SEric Schrock (void) topo_method_register(mod, pnode, svc_methods); 253*f6e214c7SGavin Maltby 254*f6e214c7SGavin Maltby if ((hdl = svc_get_handle(mod)) == NULL) 255*f6e214c7SGavin Maltby goto out; 256*f6e214c7SGavin Maltby 257*f6e214c7SGavin Maltby if ((sc = scf_scope_create(hdl)) == NULL || 258*f6e214c7SGavin Maltby (svc = scf_service_create(hdl)) == NULL || 259*f6e214c7SGavin Maltby (inst = scf_instance_create(hdl)) == NULL || 260*f6e214c7SGavin Maltby (svc_iter = scf_iter_create(hdl)) == NULL || 261*f6e214c7SGavin Maltby (inst_iter = scf_iter_create(hdl)) == NULL) 262*f6e214c7SGavin Maltby goto out; 263*f6e214c7SGavin Maltby 264*f6e214c7SGavin Maltby if (scf_handle_get_scope(hdl, SCF_SCOPE_LOCAL, sc) != 0) 265*f6e214c7SGavin Maltby goto out; 266*f6e214c7SGavin Maltby 267*f6e214c7SGavin Maltby if (scf_iter_scope_services(svc_iter, sc) != 0) 268*f6e214c7SGavin Maltby goto out; 269*f6e214c7SGavin Maltby 270*f6e214c7SGavin Maltby while (scf_iter_next_service(svc_iter, svc) == 1) { 271*f6e214c7SGavin Maltby if (scf_iter_service_instances(inst_iter, svc) != 0) 272*f6e214c7SGavin Maltby continue; 273*f6e214c7SGavin Maltby 274*f6e214c7SGavin Maltby if ((slen = scf_service_to_fmri(svc, NULL, 0)) < 0) 275*f6e214c7SGavin Maltby continue; 276*f6e214c7SGavin Maltby 277*f6e214c7SGavin Maltby if ((sfmri = topo_mod_zalloc(mod, slen + 1)) == NULL) { 278*f6e214c7SGavin Maltby (void) topo_mod_seterrno(mod, EMOD_NOMEM); 279*f6e214c7SGavin Maltby goto out; 280*f6e214c7SGavin Maltby } 281*f6e214c7SGavin Maltby if (scf_service_to_fmri(svc, sfmri, slen + 1) == -1) 282*f6e214c7SGavin Maltby goto out; 283*f6e214c7SGavin Maltby 284*f6e214c7SGavin Maltby if ((svc_node = svc_create_node(mod, pnode, sfmri)) == NULL) { 285*f6e214c7SGavin Maltby topo_mod_free(mod, sfmri, slen + 1); 286*f6e214c7SGavin Maltby /* topo mod errno set */ 287*f6e214c7SGavin Maltby goto out; 288*f6e214c7SGavin Maltby } 289*f6e214c7SGavin Maltby 290*f6e214c7SGavin Maltby while (scf_iter_next_instance(inst_iter, inst) == 1) { 291*f6e214c7SGavin Maltby if ((ilen = scf_instance_to_fmri(inst, NULL, 0)) < 0) 292*f6e214c7SGavin Maltby continue; 293*f6e214c7SGavin Maltby 294*f6e214c7SGavin Maltby if ((ifmri = topo_mod_zalloc(mod, ilen + 1)) 295*f6e214c7SGavin Maltby == NULL) { 296*f6e214c7SGavin Maltby (void) topo_mod_seterrno(mod, EMOD_NOMEM); 297*f6e214c7SGavin Maltby topo_mod_free(mod, sfmri, slen + 1); 298*f6e214c7SGavin Maltby goto out; 299*f6e214c7SGavin Maltby } 300*f6e214c7SGavin Maltby if (scf_instance_to_fmri(inst, ifmri, ilen + 1) == -1) 301*f6e214c7SGavin Maltby goto out; 302*f6e214c7SGavin Maltby 303*f6e214c7SGavin Maltby if ((svc_node = svc_create_node(mod, svc_node, ifmri)) 304*f6e214c7SGavin Maltby == NULL) { 305*f6e214c7SGavin Maltby topo_mod_free(mod, sfmri, slen + 1); 306*f6e214c7SGavin Maltby topo_mod_free(mod, ifmri, ilen + 1); 307*f6e214c7SGavin Maltby /* topo mod errno set */ 308*f6e214c7SGavin Maltby goto out; 309*f6e214c7SGavin Maltby } 310*f6e214c7SGavin Maltby topo_mod_free(mod, ifmri, ilen + 1); 311*f6e214c7SGavin Maltby } 312*f6e214c7SGavin Maltby topo_mod_free(mod, sfmri, slen + 1); 313*f6e214c7SGavin Maltby } 314*f6e214c7SGavin Maltby ret = 0; 315*f6e214c7SGavin Maltby out: 316*f6e214c7SGavin Maltby scf_scope_destroy(sc); 317*f6e214c7SGavin Maltby scf_service_destroy(svc); 318*f6e214c7SGavin Maltby scf_instance_destroy(inst); 319*f6e214c7SGavin Maltby scf_iter_destroy(svc_iter); 320*f6e214c7SGavin Maltby scf_iter_destroy(inst_iter); 321*f6e214c7SGavin Maltby 322*f6e214c7SGavin Maltby return (ret); 32395efa359SEric Schrock } 32495efa359SEric Schrock 32595efa359SEric Schrock static void 32695efa359SEric Schrock svc_release(topo_mod_t *mod, tnode_t *node) 32795efa359SEric Schrock { 32895efa359SEric Schrock topo_method_unregister_all(mod, node); 32995efa359SEric Schrock } 33095efa359SEric Schrock 33195efa359SEric Schrock static boolean_t 33295efa359SEric Schrock svc_component_valid(const char *str) 33395efa359SEric Schrock { 33495efa359SEric Schrock if (str == NULL) 33595efa359SEric Schrock return (B_TRUE); 33695efa359SEric Schrock 33795efa359SEric Schrock if (*str == '\0') 33895efa359SEric Schrock return (B_FALSE); 33995efa359SEric Schrock 34095efa359SEric Schrock if (strpbrk(str, "@/:") != NULL) 34195efa359SEric Schrock return (B_FALSE); 34295efa359SEric Schrock 34395efa359SEric Schrock return (B_TRUE); 34495efa359SEric Schrock } 34595efa359SEric Schrock 346*f6e214c7SGavin Maltby static int 347*f6e214c7SGavin Maltby svc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version, 348*f6e214c7SGavin Maltby nvlist_t *in, nvlist_t **out) 349*f6e214c7SGavin Maltby { 350*f6e214c7SGavin Maltby char *svc_name, *svc_inst = NULL; 351*f6e214c7SGavin Maltby nvlist_t *rsrc, *args; 352*f6e214c7SGavin Maltby char *pgroup, *pname; 353*f6e214c7SGavin Maltby tnode_t *svc_node; 354*f6e214c7SGavin Maltby char *search; 355*f6e214c7SGavin Maltby size_t len; 356*f6e214c7SGavin Maltby int err; 357*f6e214c7SGavin Maltby 358*f6e214c7SGavin Maltby if (version > TOPO_METH_PROP_GET_VERSION) 359*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 360*f6e214c7SGavin Maltby 361*f6e214c7SGavin Maltby err = nvlist_lookup_string(in, TOPO_PROP_GROUP, &pgroup); 362*f6e214c7SGavin Maltby err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME, &pname); 363*f6e214c7SGavin Maltby err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &rsrc); 364*f6e214c7SGavin Maltby if (err != 0) 365*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 366*f6e214c7SGavin Maltby 367*f6e214c7SGavin Maltby /* 368*f6e214c7SGavin Maltby * Private args to prop method are optional 369*f6e214c7SGavin Maltby */ 370*f6e214c7SGavin Maltby if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &args)) != 0) { 371*f6e214c7SGavin Maltby if (err != ENOENT) 372*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 373*f6e214c7SGavin Maltby else 374*f6e214c7SGavin Maltby args = NULL; 375*f6e214c7SGavin Maltby } 376*f6e214c7SGavin Maltby 377*f6e214c7SGavin Maltby /* 378*f6e214c7SGavin Maltby * Lookup a topo node named svc:/svc_name[:svc_inst] 379*f6e214c7SGavin Maltby */ 380*f6e214c7SGavin Maltby if (nvlist_lookup_string(rsrc, FM_FMRI_SVC_NAME, &svc_name) != 0) 381*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 382*f6e214c7SGavin Maltby 383*f6e214c7SGavin Maltby (void) nvlist_lookup_string(rsrc, FM_FMRI_SVC_INSTANCE, &svc_inst); 384*f6e214c7SGavin Maltby 385*f6e214c7SGavin Maltby len = 5 + strlen(svc_name) + 386*f6e214c7SGavin Maltby (svc_inst != NULL ? 1 + strlen(svc_inst) : 0) + 1; 387*f6e214c7SGavin Maltby 388*f6e214c7SGavin Maltby if ((search = topo_mod_alloc(mod, len)) == NULL) 389*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, EMOD_NOMEM)); 390*f6e214c7SGavin Maltby 391*f6e214c7SGavin Maltby (void) snprintf(search, len, "svc:/%s", svc_name); 392*f6e214c7SGavin Maltby svc_node = topo_node_lookup(node, (const char *)search, 0); 393*f6e214c7SGavin Maltby 394*f6e214c7SGavin Maltby if (svc_node == NULL) { 395*f6e214c7SGavin Maltby topo_mod_free(mod, search, len); 396*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, EMOD_NODE_NOENT)); 397*f6e214c7SGavin Maltby } 398*f6e214c7SGavin Maltby 399*f6e214c7SGavin Maltby if (svc_inst != NULL) { 400*f6e214c7SGavin Maltby (void) snprintf(search, len, "svc:/%s:%s", svc_name, svc_inst); 401*f6e214c7SGavin Maltby svc_node = topo_node_lookup(svc_node, (const char *)search, 0); 402*f6e214c7SGavin Maltby if (svc_node == NULL) { 403*f6e214c7SGavin Maltby topo_mod_free(mod, search, len); 404*f6e214c7SGavin Maltby return (topo_mod_seterrno(mod, EMOD_NODE_NOENT)); 405*f6e214c7SGavin Maltby } 406*f6e214c7SGavin Maltby } 407*f6e214c7SGavin Maltby 408*f6e214c7SGavin Maltby topo_mod_free(mod, search, len); 409*f6e214c7SGavin Maltby 410*f6e214c7SGavin Maltby err = 0; 411*f6e214c7SGavin Maltby (void) topo_prop_getprop(svc_node, pgroup, pname, args, out, &err); 412*f6e214c7SGavin Maltby 413*f6e214c7SGavin Maltby return (err); 414*f6e214c7SGavin Maltby } 415*f6e214c7SGavin Maltby 41695efa359SEric Schrock /*ARGSUSED*/ 41795efa359SEric Schrock static int 41895efa359SEric Schrock svc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 41995efa359SEric Schrock nvlist_t *nvl, nvlist_t **out) 42095efa359SEric Schrock { 42195efa359SEric Schrock uint8_t scheme_version; 42295efa359SEric Schrock char *scope = NULL; 42395efa359SEric Schrock char *fqn = NULL; 42495efa359SEric Schrock char *contract = NULL; 42595efa359SEric Schrock char *instance = NULL; 42695efa359SEric Schrock char *service; 42795efa359SEric Schrock int err; 42895efa359SEric Schrock char *buf = NULL; 42995efa359SEric Schrock size_t buflen = 0; 43095efa359SEric Schrock ssize_t size = 0; 43195efa359SEric Schrock nvlist_t *fmristr; 43295efa359SEric Schrock 43395efa359SEric Schrock if (version > TOPO_METH_NVL2STR_VERSION) 43495efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 43595efa359SEric Schrock 43695efa359SEric Schrock if (nvlist_lookup_uint8(nvl, FM_VERSION, &scheme_version) != 0 || 43795efa359SEric Schrock scheme_version > FM_SVC_SCHEME_VERSION) 43895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 43995efa359SEric Schrock 44095efa359SEric Schrock /* 44195efa359SEric Schrock * Check for optional members. 44295efa359SEric Schrock */ 44395efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_INSTANCE, &instance); 44495efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(instance)) 44595efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 44695efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_AUTH_SCOPE, &scope); 44795efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(scope)) 44895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 44995efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_AUTH_SYSTEM_FQN, &fqn); 45095efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(scope)) 45195efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 45295efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_CONTRACT_ID, &contract); 45395efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(contract)) 45495efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 45595efa359SEric Schrock 45695efa359SEric Schrock /* 45795efa359SEric Schrock * Get the service name. 45895efa359SEric Schrock */ 45995efa359SEric Schrock if (nvlist_lookup_string(nvl, FM_FMRI_SVC_NAME, &service) != 0) 46095efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 46195efa359SEric Schrock 46295efa359SEric Schrock /* 46395efa359SEric Schrock * We make two passes through this code. The first time through we 46495efa359SEric Schrock * calculate the size of buffer that we'll need, and the second time 46595efa359SEric Schrock * through we fill it in. 46695efa359SEric Schrock */ 46795efa359SEric Schrock again: 46895efa359SEric Schrock /* 46995efa359SEric Schrock * svc://[scope@][system-fqn] 47095efa359SEric Schrock */ 47195efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_SVC, 47295efa359SEric Schrock NULL, "://"); 47395efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, scope, NULL, "@"); 47495efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, fqn, NULL, NULL); 47595efa359SEric Schrock 47695efa359SEric Schrock /* svc path */ 47795efa359SEric Schrock if (*service == '\0') 47895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 47995efa359SEric Schrock 48095efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, service, "/", NULL); 48195efa359SEric Schrock 48295efa359SEric Schrock /* [:instance][@contract-id] */ 48395efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, instance, ":", NULL); 48495efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, contract, "@", NULL); 48595efa359SEric Schrock 48695efa359SEric Schrock if (buf == NULL) { 48795efa359SEric Schrock if ((buf = topo_mod_alloc(mod, size + 1)) == NULL) 48895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 48995efa359SEric Schrock 49095efa359SEric Schrock buflen = size + 1; 49195efa359SEric Schrock size = 0; 49295efa359SEric Schrock goto again; 49395efa359SEric Schrock } 49495efa359SEric Schrock 49595efa359SEric Schrock /* 49695efa359SEric Schrock * Construct the nvlist to return as the result. 49795efa359SEric Schrock */ 49895efa359SEric Schrock if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 49995efa359SEric Schrock topo_mod_strfree(mod, buf); 50095efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 50195efa359SEric Schrock } 50295efa359SEric Schrock 50395efa359SEric Schrock if (nvlist_add_string(fmristr, "fmri-string", buf) != 0) { 50495efa359SEric Schrock topo_mod_strfree(mod, buf); 50595efa359SEric Schrock nvlist_free(fmristr); 50695efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 50795efa359SEric Schrock } 50895efa359SEric Schrock topo_mod_strfree(mod, buf); 50995efa359SEric Schrock *out = fmristr; 51095efa359SEric Schrock 51195efa359SEric Schrock return (0); 51295efa359SEric Schrock } 51395efa359SEric Schrock 51495efa359SEric Schrock /*ARGSUSED*/ 51595efa359SEric Schrock static int 51695efa359SEric Schrock svc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 51795efa359SEric Schrock nvlist_t *in, nvlist_t **out) 51895efa359SEric Schrock { 51995efa359SEric Schrock nvlist_t *fmri; 52095efa359SEric Schrock char *str, *loc, val; 52195efa359SEric Schrock 52295efa359SEric Schrock if (version > TOPO_METH_STR2NVL_VERSION) 52395efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 52495efa359SEric Schrock 52595efa359SEric Schrock if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 52695efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 52795efa359SEric Schrock 52895efa359SEric Schrock if (strncmp(str, "svc://", 6) != 0) 52995efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 53095efa359SEric Schrock 53195efa359SEric Schrock if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 53295efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 53395efa359SEric Schrock 53495efa359SEric Schrock str += 6; 53595efa359SEric Schrock if ((loc = strpbrk(str, "@/")) == NULL) 53695efa359SEric Schrock goto malformed; 53795efa359SEric Schrock 53895efa359SEric Schrock if (*loc == '@') { 53995efa359SEric Schrock /* scope */ 54095efa359SEric Schrock *loc = '\0'; 54195efa359SEric Schrock if (!svc_component_valid(str)) { 54295efa359SEric Schrock *loc = '@'; 54395efa359SEric Schrock goto malformed; 54495efa359SEric Schrock } 54595efa359SEric Schrock 54695efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_AUTH_SCOPE, str) != 0) { 54795efa359SEric Schrock *loc = '@'; 54895efa359SEric Schrock goto nomem; 54995efa359SEric Schrock } 55095efa359SEric Schrock 55195efa359SEric Schrock *loc = '@'; 55295efa359SEric Schrock str = loc + 1; 55395efa359SEric Schrock if ((loc = strchr(str, '/')) == NULL) 55495efa359SEric Schrock goto malformed; 55595efa359SEric Schrock } 55695efa359SEric Schrock 55795efa359SEric Schrock if (loc != str) { 55895efa359SEric Schrock /* system-fqn */ 55995efa359SEric Schrock *loc = '\0'; 56095efa359SEric Schrock if (!svc_component_valid(str)) { 56195efa359SEric Schrock *loc = '/'; 56295efa359SEric Schrock goto malformed; 56395efa359SEric Schrock } 56495efa359SEric Schrock 56595efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_AUTH_SYSTEM_FQN, 56695efa359SEric Schrock str) != 0) { 56795efa359SEric Schrock *loc = '/'; 56895efa359SEric Schrock goto nomem; 56995efa359SEric Schrock } 57095efa359SEric Schrock 57195efa359SEric Schrock *loc = '/'; 57295efa359SEric Schrock } 57395efa359SEric Schrock 57495efa359SEric Schrock str = loc + 1; 57595efa359SEric Schrock loc = strpbrk(str, ":@"); 57695efa359SEric Schrock 57795efa359SEric Schrock if (str[0] == '\0' || loc == str) 57895efa359SEric Schrock goto malformed; 57995efa359SEric Schrock 58095efa359SEric Schrock if (loc != NULL) { 58195efa359SEric Schrock val = *loc; 58295efa359SEric Schrock *loc = '\0'; 58395efa359SEric Schrock } 58495efa359SEric Schrock 58595efa359SEric Schrock /* service name */ 58695efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_NAME, str) != 0) { 58795efa359SEric Schrock if (loc != NULL) 58895efa359SEric Schrock *loc = val; 58995efa359SEric Schrock goto nomem; 59095efa359SEric Schrock } 59195efa359SEric Schrock 59295efa359SEric Schrock if (loc != NULL) 59395efa359SEric Schrock *loc = val; 59495efa359SEric Schrock 59595efa359SEric Schrock if (loc != NULL && *loc == ':') { 59695efa359SEric Schrock /* instance */ 59795efa359SEric Schrock str = loc + 1; 59895efa359SEric Schrock if (str[0] == '\0' || str[0] == '@') 59995efa359SEric Schrock goto malformed; 60095efa359SEric Schrock 60195efa359SEric Schrock loc = strchr(str, '@'); 60295efa359SEric Schrock if (loc != NULL) 60395efa359SEric Schrock *loc = '\0'; 60495efa359SEric Schrock 60595efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_INSTANCE, 60695efa359SEric Schrock str) != 0) { 60795efa359SEric Schrock if (loc != NULL) 60895efa359SEric Schrock *loc = '@'; 60995efa359SEric Schrock goto nomem; 61095efa359SEric Schrock } 61195efa359SEric Schrock 61295efa359SEric Schrock if (loc != NULL) 61395efa359SEric Schrock *loc = '@'; 61495efa359SEric Schrock } 61595efa359SEric Schrock 61695efa359SEric Schrock if (loc != NULL) { 61795efa359SEric Schrock /* contract-id */ 61895efa359SEric Schrock assert(*loc == '@'); 61995efa359SEric Schrock str = loc + 1; 62095efa359SEric Schrock if (str[0] == '\0') 62195efa359SEric Schrock goto malformed; 62295efa359SEric Schrock 62395efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_CONTRACT_ID, 62495efa359SEric Schrock str) != 0) { 62595efa359SEric Schrock goto nomem; 62695efa359SEric Schrock } 62795efa359SEric Schrock } 62895efa359SEric Schrock 62995efa359SEric Schrock if (nvlist_add_uint8(fmri, FM_VERSION, FM_SVC_SCHEME_VERSION) != 0 || 63095efa359SEric Schrock nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SVC) != 0) 63195efa359SEric Schrock goto nomem; 63295efa359SEric Schrock 63395efa359SEric Schrock *out = fmri; 63495efa359SEric Schrock return (0); 63595efa359SEric Schrock 63695efa359SEric Schrock malformed: 63795efa359SEric Schrock nvlist_free(fmri); 63895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 63995efa359SEric Schrock 64095efa359SEric Schrock nomem: 64195efa359SEric Schrock nvlist_free(fmri); 64295efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 64395efa359SEric Schrock } 64495efa359SEric Schrock 64595efa359SEric Schrock /* 646*f6e214c7SGavin Maltby * This common function is shared by all consumers (present, replaced, 647*f6e214c7SGavin Maltby * service state and unusable). 648*f6e214c7SGavin Maltby * 649*f6e214c7SGavin Maltby * svc_get_state succeeds 650*f6e214c7SGavin Maltby * Case with FMD_SERVICE_STATE_* 651*f6e214c7SGavin Maltby * ---------------------------- ------------------------ 652*f6e214c7SGavin Maltby * svc name deleted UNKNOWN 653*f6e214c7SGavin Maltby * svc name not found UNKNOWN 654*f6e214c7SGavin Maltby * no fmri instance OK 655*f6e214c7SGavin Maltby * instance deleted UNKNOWN 656*f6e214c7SGavin Maltby * instance not found UNKNOWN 657*f6e214c7SGavin Maltby * 658*f6e214c7SGavin Maltby * If none of the above apply and this is a call from the "present" 659*f6e214c7SGavin Maltby * or "replaced" method (presence_only == B_TRUE) then 660*f6e214c7SGavin Maltby * svc_get_state returns FMD_SERVICE_STATE_OK. 661*f6e214c7SGavin Maltby * 662*f6e214c7SGavin Maltby * The "present" method maps a svc_get_state return of UNKNOWN to 663*f6e214c7SGavin Maltby * "not present" and a svc_get_state return of OK to "present". 664*f6e214c7SGavin Maltby * 665*f6e214c7SGavin Maltby * The "replaced" methods maps a return of UNKNOWN to FMD_OBJ_STATE_NOT_PRESENT 666*f6e214c7SGavin Maltby * and OK to FMD_OBJ_STATE_UNKNOWN. 667*f6e214c7SGavin Maltby * 668*f6e214c7SGavin Maltby * For the "service state" and "unusable" methods svc_get_state goes on 669*f6e214c7SGavin Maltby * to return the instance state as below, and the two methods map that 670*f6e214c7SGavin Maltby * result as in the last two columns of the following table: 671*f6e214c7SGavin Maltby * 672*f6e214c7SGavin Maltby * svc_get_state succeeds Service 673*f6e214c7SGavin Maltby * Instance state with FMD_SERVICE_STATE_* State Unusable 674*f6e214c7SGavin Maltby * -------------- ------------------------------- --------------- -------- 675*f6e214c7SGavin Maltby * none OK OK 676*f6e214c7SGavin Maltby * uninitialized OK OK 677*f6e214c7SGavin Maltby * maintenance UNUSABLE UNUSABLE Yes 678*f6e214c7SGavin Maltby * offline OK OK 679*f6e214c7SGavin Maltby * disabled OK OK 680*f6e214c7SGavin Maltby * online OK OK 681*f6e214c7SGavin Maltby * degraded DEGRADED DEGRADED 682*f6e214c7SGavin Maltby * legacy_run OK (XXX can we see this?) OK 683*f6e214c7SGavin Maltby * 684*f6e214c7SGavin Maltby * Note that *only* "maintenance" state should map to an unusable service state 685*f6e214c7SGavin Maltby * or unusable status. That's because a service entering maintenance state 686*f6e214c7SGavin Maltby * is modelled as a defect fault diagnosis in FMA, but there is no 687*f6e214c7SGavin Maltby * corresponding isolation action from a response agent since the the service 688*f6e214c7SGavin Maltby * is already isolated by virtue of being in maintenance state. Any transition 689*f6e214c7SGavin Maltby * from maintenance state, even to offline, is considered a repair. If on 690*f6e214c7SGavin Maltby * repair fmd does not see the service usable again then the case hangs 691*f6e214c7SGavin Maltby * around in the "resolved but not all resources back online" state and 692*f6e214c7SGavin Maltby * further maintenance events for this service will not show up in fmd state 693*f6e214c7SGavin Maltby * because case duplicate checking code will find the old case. 69495efa359SEric Schrock */ 695*f6e214c7SGavin Maltby 69695efa359SEric Schrock static int 69795efa359SEric Schrock svc_get_state(topo_mod_t *mod, nvlist_t *fmri, boolean_t presence_only, 69895efa359SEric Schrock int *ret) 69995efa359SEric Schrock { 7009f342a5aSEric Schrock scf_handle_t *hdl; 70195efa359SEric Schrock uint8_t fmversion; 70295efa359SEric Schrock char *instance, *name; 70395efa359SEric Schrock scf_service_t *svc = NULL; 70495efa359SEric Schrock scf_scope_t *scope = NULL; 70595efa359SEric Schrock scf_instance_t *inst = NULL; 70695efa359SEric Schrock scf_property_t *prop = NULL; 70795efa359SEric Schrock scf_iter_t *iter = NULL; 70895efa359SEric Schrock scf_value_t *val = NULL; 70995efa359SEric Schrock scf_propertygroup_t *pg = NULL; 71095efa359SEric Schrock int err, retval = 0; 71195efa359SEric Schrock ssize_t len; 71295efa359SEric Schrock char *state; 71395efa359SEric Schrock 7149f342a5aSEric Schrock if ((hdl = svc_get_handle(mod)) == NULL) 7159f342a5aSEric Schrock return (-1); 7169f342a5aSEric Schrock 71795efa359SEric Schrock if (nvlist_lookup_uint8(fmri, FM_VERSION, &fmversion) != 0 || 71895efa359SEric Schrock fmversion > FM_SVC_SCHEME_VERSION || 71995efa359SEric Schrock nvlist_lookup_string(fmri, FM_FMRI_SVC_NAME, &name) != 0) 72095efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 72195efa359SEric Schrock 72295efa359SEric Schrock if ((svc = scf_service_create(hdl)) == NULL || 72395efa359SEric Schrock (inst = scf_instance_create(hdl)) == NULL || 72495efa359SEric Schrock (scope = scf_scope_create(hdl)) == NULL || 72595efa359SEric Schrock (prop = scf_property_create(hdl)) == NULL || 72695efa359SEric Schrock (iter = scf_iter_create(hdl)) == NULL || 72795efa359SEric Schrock (pg = scf_pg_create(hdl)) == NULL || 72895efa359SEric Schrock (val = scf_value_create(hdl)) == NULL) 72995efa359SEric Schrock goto error; 73095efa359SEric Schrock 73195efa359SEric Schrock if (scf_handle_get_scope(hdl, SCF_SCOPE_LOCAL, scope) != 0) 73295efa359SEric Schrock goto error; 73395efa359SEric Schrock 73495efa359SEric Schrock /* 73595efa359SEric Schrock * If we fail to get the service due to _DELETED or _NOT_FOUND, then we 73695efa359SEric Schrock * treat this as not present. 73795efa359SEric Schrock */ 73895efa359SEric Schrock if (scf_scope_get_service(scope, name, svc) != 0) { 73995efa359SEric Schrock err = scf_error(); 74095efa359SEric Schrock if (err == SCF_ERROR_NOT_FOUND || err == SCF_ERROR_DELETED) { 74195efa359SEric Schrock *ret = FMD_SERVICE_STATE_UNKNOWN; 74295efa359SEric Schrock goto out; 74395efa359SEric Schrock } else { 74495efa359SEric Schrock goto error; 74595efa359SEric Schrock } 74695efa359SEric Schrock } 74795efa359SEric Schrock 74895efa359SEric Schrock if (nvlist_lookup_string(fmri, FM_FMRI_SVC_INSTANCE, &instance) != 0) { 74995efa359SEric Schrock *ret = FMD_SERVICE_STATE_OK; 75095efa359SEric Schrock goto out; 75195efa359SEric Schrock } 75295efa359SEric Schrock 75395efa359SEric Schrock /* 75495efa359SEric Schrock * Again, check for _DELETED or _NOT_FOUND. 75595efa359SEric Schrock */ 75695efa359SEric Schrock if (scf_service_get_instance(svc, instance, inst) != 0) { 75795efa359SEric Schrock err = scf_error(); 75895efa359SEric Schrock if (err == SCF_ERROR_NOT_FOUND || err == SCF_ERROR_DELETED) { 75995efa359SEric Schrock *ret = FMD_SERVICE_STATE_UNKNOWN; 76095efa359SEric Schrock goto out; 76195efa359SEric Schrock } else { 76295efa359SEric Schrock goto error; 76395efa359SEric Schrock } 76495efa359SEric Schrock } 76595efa359SEric Schrock 76695efa359SEric Schrock /* 76795efa359SEric Schrock * For presence, we are done. Otherwise, we need to get the current 76895efa359SEric Schrock * state of the instance. 76995efa359SEric Schrock */ 77095efa359SEric Schrock if (presence_only) { 77195efa359SEric Schrock *ret = FMD_SERVICE_STATE_OK; 77295efa359SEric Schrock goto out; 77395efa359SEric Schrock } 77495efa359SEric Schrock 77595efa359SEric Schrock if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0 || 77695efa359SEric Schrock scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) != 0 || 77795efa359SEric Schrock scf_iter_property_values(iter, prop) != 0 || 77895efa359SEric Schrock scf_iter_next_value(iter, val) != 1) 77995efa359SEric Schrock goto error; 78095efa359SEric Schrock 78195efa359SEric Schrock if ((len = scf_value_get_astring(val, NULL, 0)) < 0) 78295efa359SEric Schrock goto error; 78395efa359SEric Schrock 78495efa359SEric Schrock state = alloca(len + 1); 78595efa359SEric Schrock if (scf_value_get_astring(val, state, len + 1) < 0) 78695efa359SEric Schrock goto error; 78795efa359SEric Schrock 788*f6e214c7SGavin Maltby if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { 78995efa359SEric Schrock *ret = FMD_SERVICE_STATE_UNUSABLE; 790*f6e214c7SGavin Maltby } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) { 79195efa359SEric Schrock *ret = FMD_SERVICE_STATE_DEGRADED; 792*f6e214c7SGavin Maltby } else { 79395efa359SEric Schrock *ret = FMD_SERVICE_STATE_OK; 794*f6e214c7SGavin Maltby } 79595efa359SEric Schrock goto out; 79695efa359SEric Schrock 79795efa359SEric Schrock error: 79895efa359SEric Schrock retval = -1; 79995efa359SEric Schrock out: 80095efa359SEric Schrock scf_value_destroy(val); 80195efa359SEric Schrock scf_pg_destroy(pg); 80295efa359SEric Schrock scf_iter_destroy(iter); 80395efa359SEric Schrock scf_property_destroy(prop); 80495efa359SEric Schrock scf_instance_destroy(inst); 80595efa359SEric Schrock scf_scope_destroy(scope); 80695efa359SEric Schrock scf_service_destroy(svc); 80795efa359SEric Schrock return (retval); 80895efa359SEric Schrock } 80995efa359SEric Schrock 81095efa359SEric Schrock /*ARGSUSED*/ 81195efa359SEric Schrock static int 81295efa359SEric Schrock svc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 81395efa359SEric Schrock nvlist_t *in, nvlist_t **out) 81495efa359SEric Schrock { 81595efa359SEric Schrock int state; 81695efa359SEric Schrock 81795efa359SEric Schrock if (version > TOPO_METH_PRESENT_VERSION) 81895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 81995efa359SEric Schrock 82095efa359SEric Schrock if (svc_get_state(mod, in, B_TRUE, &state) != 0) 82195efa359SEric Schrock return (-1); 82295efa359SEric Schrock 82395efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 82495efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 82595efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_PRESENT_RET, 82695efa359SEric Schrock state != FMD_SERVICE_STATE_UNKNOWN) != 0) { 82795efa359SEric Schrock nvlist_free(*out); 82895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 82995efa359SEric Schrock } 83095efa359SEric Schrock 83195efa359SEric Schrock return (0); 83295efa359SEric Schrock } 83395efa359SEric Schrock 83495efa359SEric Schrock /*ARGSUSED*/ 83595efa359SEric Schrock static int 83695efa359SEric Schrock svc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, 83795efa359SEric Schrock nvlist_t *in, nvlist_t **out) 83895efa359SEric Schrock { 83995efa359SEric Schrock int state; 84095efa359SEric Schrock 84195efa359SEric Schrock if (version > TOPO_METH_REPLACED_VERSION) 84295efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 84395efa359SEric Schrock 84495efa359SEric Schrock if (svc_get_state(mod, in, B_TRUE, &state) != 0) 84595efa359SEric Schrock return (-1); 84695efa359SEric Schrock 84795efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 84895efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 84995efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, 85095efa359SEric Schrock state == FMD_SERVICE_STATE_UNKNOWN ? 85195efa359SEric Schrock FMD_OBJ_STATE_NOT_PRESENT : FMD_OBJ_STATE_UNKNOWN) != 0) { 85295efa359SEric Schrock nvlist_free(*out); 85395efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 85495efa359SEric Schrock } 85595efa359SEric Schrock 85695efa359SEric Schrock return (0); 85795efa359SEric Schrock } 85895efa359SEric Schrock 85995efa359SEric Schrock /*ARGSUSED*/ 86095efa359SEric Schrock static int 86195efa359SEric Schrock svc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version, 86295efa359SEric Schrock nvlist_t *in, nvlist_t **out) 86395efa359SEric Schrock { 86495efa359SEric Schrock int state; 86595efa359SEric Schrock 86695efa359SEric Schrock if (version > TOPO_METH_SERVICE_STATE_VERSION) 86795efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 86895efa359SEric Schrock 86995efa359SEric Schrock if (svc_get_state(mod, in, B_FALSE, &state) != 0) 87095efa359SEric Schrock return (-1); 87195efa359SEric Schrock 87295efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 87395efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 87495efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_SERVICE_STATE_RET, 87595efa359SEric Schrock state) != 0) { 87695efa359SEric Schrock nvlist_free(*out); 87795efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 87895efa359SEric Schrock } 87995efa359SEric Schrock 88095efa359SEric Schrock return (0); 88195efa359SEric Schrock } 88295efa359SEric Schrock 88395efa359SEric Schrock /*ARGSUSED*/ 88495efa359SEric Schrock static int 88595efa359SEric Schrock svc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 88695efa359SEric Schrock nvlist_t *in, nvlist_t **out) 88795efa359SEric Schrock { 88895efa359SEric Schrock int state; 88995efa359SEric Schrock 89095efa359SEric Schrock if (version > TOPO_METH_UNUSABLE_VERSION) 89195efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 89295efa359SEric Schrock 89395efa359SEric Schrock if (svc_get_state(mod, in, B_FALSE, &state) != 0) 89495efa359SEric Schrock return (-1); 89595efa359SEric Schrock 89695efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 89795efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 89895efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_UNUSABLE_RET, 89995efa359SEric Schrock (state == FMD_SERVICE_STATE_UNKNOWN || 90095efa359SEric Schrock state == FMD_SERVICE_STATE_UNUSABLE)) != 0) { 90195efa359SEric Schrock nvlist_free(*out); 90295efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 90395efa359SEric Schrock } 90495efa359SEric Schrock 90595efa359SEric Schrock return (0); 90695efa359SEric Schrock } 907