1*95efa359SEric Schrock /* 2*95efa359SEric Schrock * CDDL HEADER START 3*95efa359SEric Schrock * 4*95efa359SEric Schrock * The contents of this file are subject to the terms of the 5*95efa359SEric Schrock * Common Development and Distribution License (the "License"). 6*95efa359SEric Schrock * You may not use this file except in compliance with the License. 7*95efa359SEric Schrock * 8*95efa359SEric Schrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*95efa359SEric Schrock * or http://www.opensolaris.org/os/licensing. 10*95efa359SEric Schrock * See the License for the specific language governing permissions 11*95efa359SEric Schrock * and limitations under the License. 12*95efa359SEric Schrock * 13*95efa359SEric Schrock * When distributing Covered Code, include this CDDL HEADER in each 14*95efa359SEric Schrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*95efa359SEric Schrock * If applicable, add the following below this CDDL HEADER, with the 16*95efa359SEric Schrock * fields enclosed by brackets "[]" replaced with your own identifying 17*95efa359SEric Schrock * information: Portions Copyright [yyyy] [name of copyright owner] 18*95efa359SEric Schrock * 19*95efa359SEric Schrock * CDDL HEADER END 20*95efa359SEric Schrock */ 21*95efa359SEric Schrock 22*95efa359SEric Schrock /* 23*95efa359SEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*95efa359SEric Schrock * Use is subject to license terms. 25*95efa359SEric Schrock */ 26*95efa359SEric Schrock 27*95efa359SEric Schrock /* 28*95efa359SEric Schrock * This provides the basic mechanisms (str2nvl and nvl2str) for dealing with 29*95efa359SEric Schrock * the service schema. The official version of a svc FMRI has the form: 30*95efa359SEric Schrock * 31*95efa359SEric Schrock * svc://[scope@][system-fqn]/service[:instance][@contract-id] 32*95efa359SEric Schrock * 33*95efa359SEric Schrock * Where 'service' is a slash-delimited list of names. Of these fields, the 34*95efa359SEric Schrock * scope, constract-id, and system-fqn are rarely used, leaving the much more 35*95efa359SEric Schrock * common form such as: 36*95efa359SEric Schrock * 37*95efa359SEric Schrock * svc:///network/ssh:default 38*95efa359SEric Schrock * 39*95efa359SEric Schrock * Note that the SMF software typically uses a shorthard form, where the 40*95efa359SEric Schrock * authority is elided (svc:/network/ssh:default). As this module deals with 41*95efa359SEric Schrock * FMA FMRIs, we only support fully specified FMRIs. 42*95efa359SEric Schrock * 43*95efa359SEric Schrock * This module does not support enumeration, but implements methods for FMRI 44*95efa359SEric Schrock * state (present, unusable, service state, and replaced). 45*95efa359SEric Schrock */ 46*95efa359SEric Schrock 47*95efa359SEric Schrock #include <fm/topo_mod.h> 48*95efa359SEric Schrock #include <fm/fmd_fmri.h> 49*95efa359SEric Schrock #include <sys/fm/protocol.h> 50*95efa359SEric Schrock #include <topo_method.h> 51*95efa359SEric Schrock #include <topo_subr.h> 52*95efa359SEric Schrock #include <alloca.h> 53*95efa359SEric Schrock #include <assert.h> 54*95efa359SEric Schrock #include <svc.h> 55*95efa359SEric Schrock #include <strings.h> 56*95efa359SEric Schrock #include <libscf.h> 57*95efa359SEric Schrock 58*95efa359SEric Schrock static int svc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 59*95efa359SEric Schrock nvlist_t *, nvlist_t **); 60*95efa359SEric Schrock static int svc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 61*95efa359SEric Schrock nvlist_t *, nvlist_t **); 62*95efa359SEric Schrock static int svc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, 63*95efa359SEric Schrock nvlist_t *, nvlist_t **); 64*95efa359SEric Schrock static int svc_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, 65*95efa359SEric Schrock nvlist_t *, nvlist_t **); 66*95efa359SEric Schrock static int svc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t, 67*95efa359SEric Schrock nvlist_t *, nvlist_t **); 68*95efa359SEric Schrock static int svc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, 69*95efa359SEric Schrock nvlist_t *, nvlist_t **); 70*95efa359SEric Schrock static int svc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 71*95efa359SEric Schrock topo_instance_t, void *, void *); 72*95efa359SEric Schrock static void svc_release(topo_mod_t *, tnode_t *); 73*95efa359SEric Schrock 74*95efa359SEric Schrock static const topo_method_t svc_methods[] = { 75*95efa359SEric Schrock { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 76*95efa359SEric Schrock TOPO_STABILITY_INTERNAL, svc_fmri_nvl2str }, 77*95efa359SEric Schrock { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 78*95efa359SEric Schrock TOPO_STABILITY_INTERNAL, svc_fmri_str2nvl }, 79*95efa359SEric Schrock { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, 80*95efa359SEric Schrock TOPO_STABILITY_INTERNAL, svc_fmri_present }, 81*95efa359SEric Schrock { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, 82*95efa359SEric Schrock TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, 83*95efa359SEric Schrock svc_fmri_replaced }, 84*95efa359SEric Schrock { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC, 85*95efa359SEric Schrock TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL, 86*95efa359SEric Schrock svc_fmri_service_state }, 87*95efa359SEric Schrock { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 88*95efa359SEric Schrock TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, 89*95efa359SEric Schrock svc_fmri_unusable }, 90*95efa359SEric Schrock { NULL } 91*95efa359SEric Schrock }; 92*95efa359SEric Schrock 93*95efa359SEric Schrock static const topo_modops_t svc_ops = 94*95efa359SEric Schrock { svc_enum, svc_release }; 95*95efa359SEric Schrock static const topo_modinfo_t svc_info = 96*95efa359SEric Schrock { "svc", FM_FMRI_SCHEME_SVC, SVC_VERSION, &svc_ops }; 97*95efa359SEric Schrock 98*95efa359SEric Schrock static int 99*95efa359SEric Schrock svc_error(topo_mod_t *mod) 100*95efa359SEric Schrock { 101*95efa359SEric Schrock switch (scf_error()) { 102*95efa359SEric Schrock case SCF_ERROR_NO_MEMORY: 103*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 104*95efa359SEric Schrock 105*95efa359SEric Schrock default: 106*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 107*95efa359SEric Schrock } 108*95efa359SEric Schrock } 109*95efa359SEric Schrock 110*95efa359SEric Schrock int 111*95efa359SEric Schrock svc_init(topo_mod_t *mod, topo_version_t version) 112*95efa359SEric Schrock { 113*95efa359SEric Schrock scf_handle_t *hdl; 114*95efa359SEric Schrock 115*95efa359SEric Schrock if (version != SVC_VERSION) 116*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 117*95efa359SEric Schrock 118*95efa359SEric Schrock if ((hdl = scf_handle_create(SCF_VERSION)) == NULL) 119*95efa359SEric Schrock return (svc_error(mod)); 120*95efa359SEric Schrock 121*95efa359SEric Schrock if (scf_handle_bind(hdl) != 0) { 122*95efa359SEric Schrock scf_handle_destroy(hdl); 123*95efa359SEric Schrock return (svc_error(mod)); 124*95efa359SEric Schrock } 125*95efa359SEric Schrock 126*95efa359SEric Schrock if (topo_mod_register(mod, &svc_info, TOPO_VERSION) != 0) { 127*95efa359SEric Schrock topo_mod_dprintf(mod, "failed to register svc_info: " 128*95efa359SEric Schrock "%s\n", topo_mod_errmsg(mod)); 129*95efa359SEric Schrock return (-1); 130*95efa359SEric Schrock } 131*95efa359SEric Schrock 132*95efa359SEric Schrock topo_mod_setspecific(mod, hdl); 133*95efa359SEric Schrock 134*95efa359SEric Schrock return (0); 135*95efa359SEric Schrock } 136*95efa359SEric Schrock 137*95efa359SEric Schrock void 138*95efa359SEric Schrock svc_fini(topo_mod_t *mod) 139*95efa359SEric Schrock { 140*95efa359SEric Schrock scf_handle_t *hdl = topo_mod_getspecific(mod); 141*95efa359SEric Schrock 142*95efa359SEric Schrock scf_handle_destroy(hdl); 143*95efa359SEric Schrock 144*95efa359SEric Schrock topo_mod_unregister(mod); 145*95efa359SEric Schrock } 146*95efa359SEric Schrock 147*95efa359SEric Schrock /*ARGSUSED*/ 148*95efa359SEric Schrock static int 149*95efa359SEric Schrock svc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, 150*95efa359SEric Schrock topo_instance_t min, topo_instance_t max, void *notused1, void *notused2) 151*95efa359SEric Schrock { 152*95efa359SEric Schrock (void) topo_method_register(mod, pnode, svc_methods); 153*95efa359SEric Schrock return (0); 154*95efa359SEric Schrock } 155*95efa359SEric Schrock 156*95efa359SEric Schrock static void 157*95efa359SEric Schrock svc_release(topo_mod_t *mod, tnode_t *node) 158*95efa359SEric Schrock { 159*95efa359SEric Schrock topo_method_unregister_all(mod, node); 160*95efa359SEric Schrock } 161*95efa359SEric Schrock 162*95efa359SEric Schrock static boolean_t 163*95efa359SEric Schrock svc_component_valid(const char *str) 164*95efa359SEric Schrock { 165*95efa359SEric Schrock if (str == NULL) 166*95efa359SEric Schrock return (B_TRUE); 167*95efa359SEric Schrock 168*95efa359SEric Schrock if (*str == '\0') 169*95efa359SEric Schrock return (B_FALSE); 170*95efa359SEric Schrock 171*95efa359SEric Schrock if (strpbrk(str, "@/:") != NULL) 172*95efa359SEric Schrock return (B_FALSE); 173*95efa359SEric Schrock 174*95efa359SEric Schrock return (B_TRUE); 175*95efa359SEric Schrock } 176*95efa359SEric Schrock 177*95efa359SEric Schrock /*ARGSUSED*/ 178*95efa359SEric Schrock static int 179*95efa359SEric Schrock svc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 180*95efa359SEric Schrock nvlist_t *nvl, nvlist_t **out) 181*95efa359SEric Schrock { 182*95efa359SEric Schrock uint8_t scheme_version; 183*95efa359SEric Schrock char *scope = NULL; 184*95efa359SEric Schrock char *fqn = NULL; 185*95efa359SEric Schrock char *contract = NULL; 186*95efa359SEric Schrock char *instance = NULL; 187*95efa359SEric Schrock char *service; 188*95efa359SEric Schrock int err; 189*95efa359SEric Schrock char *buf = NULL; 190*95efa359SEric Schrock size_t buflen = 0; 191*95efa359SEric Schrock ssize_t size = 0; 192*95efa359SEric Schrock nvlist_t *fmristr; 193*95efa359SEric Schrock 194*95efa359SEric Schrock if (version > TOPO_METH_NVL2STR_VERSION) 195*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 196*95efa359SEric Schrock 197*95efa359SEric Schrock if (nvlist_lookup_uint8(nvl, FM_VERSION, &scheme_version) != 0 || 198*95efa359SEric Schrock scheme_version > FM_SVC_SCHEME_VERSION) 199*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 200*95efa359SEric Schrock 201*95efa359SEric Schrock /* 202*95efa359SEric Schrock * Check for optional members. 203*95efa359SEric Schrock */ 204*95efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_INSTANCE, &instance); 205*95efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(instance)) 206*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 207*95efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_AUTH_SCOPE, &scope); 208*95efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(scope)) 209*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 210*95efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_AUTH_SYSTEM_FQN, &fqn); 211*95efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(scope)) 212*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 213*95efa359SEric Schrock err = nvlist_lookup_string(nvl, FM_FMRI_SVC_CONTRACT_ID, &contract); 214*95efa359SEric Schrock if ((err != 0 && err != ENOENT) || !svc_component_valid(contract)) 215*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 216*95efa359SEric Schrock 217*95efa359SEric Schrock /* 218*95efa359SEric Schrock * Get the service name. 219*95efa359SEric Schrock */ 220*95efa359SEric Schrock if (nvlist_lookup_string(nvl, FM_FMRI_SVC_NAME, &service) != 0) 221*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 222*95efa359SEric Schrock 223*95efa359SEric Schrock /* 224*95efa359SEric Schrock * We make two passes through this code. The first time through we 225*95efa359SEric Schrock * calculate the size of buffer that we'll need, and the second time 226*95efa359SEric Schrock * through we fill it in. 227*95efa359SEric Schrock */ 228*95efa359SEric Schrock again: 229*95efa359SEric Schrock /* 230*95efa359SEric Schrock * svc://[scope@][system-fqn] 231*95efa359SEric Schrock */ 232*95efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_SVC, 233*95efa359SEric Schrock NULL, "://"); 234*95efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, scope, NULL, "@"); 235*95efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, fqn, NULL, NULL); 236*95efa359SEric Schrock 237*95efa359SEric Schrock /* svc path */ 238*95efa359SEric Schrock if (*service == '\0') 239*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 240*95efa359SEric Schrock 241*95efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, service, "/", NULL); 242*95efa359SEric Schrock 243*95efa359SEric Schrock /* [:instance][@contract-id] */ 244*95efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, instance, ":", NULL); 245*95efa359SEric Schrock topo_fmristr_build(&size, buf, buflen, contract, "@", NULL); 246*95efa359SEric Schrock 247*95efa359SEric Schrock if (buf == NULL) { 248*95efa359SEric Schrock if ((buf = topo_mod_alloc(mod, size + 1)) == NULL) 249*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 250*95efa359SEric Schrock 251*95efa359SEric Schrock buflen = size + 1; 252*95efa359SEric Schrock size = 0; 253*95efa359SEric Schrock goto again; 254*95efa359SEric Schrock } 255*95efa359SEric Schrock 256*95efa359SEric Schrock /* 257*95efa359SEric Schrock * Construct the nvlist to return as the result. 258*95efa359SEric Schrock */ 259*95efa359SEric Schrock if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 260*95efa359SEric Schrock topo_mod_strfree(mod, buf); 261*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 262*95efa359SEric Schrock } 263*95efa359SEric Schrock 264*95efa359SEric Schrock if (nvlist_add_string(fmristr, "fmri-string", buf) != 0) { 265*95efa359SEric Schrock topo_mod_strfree(mod, buf); 266*95efa359SEric Schrock nvlist_free(fmristr); 267*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 268*95efa359SEric Schrock } 269*95efa359SEric Schrock topo_mod_strfree(mod, buf); 270*95efa359SEric Schrock *out = fmristr; 271*95efa359SEric Schrock 272*95efa359SEric Schrock return (0); 273*95efa359SEric Schrock } 274*95efa359SEric Schrock 275*95efa359SEric Schrock /*ARGSUSED*/ 276*95efa359SEric Schrock static int 277*95efa359SEric Schrock svc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 278*95efa359SEric Schrock nvlist_t *in, nvlist_t **out) 279*95efa359SEric Schrock { 280*95efa359SEric Schrock nvlist_t *fmri; 281*95efa359SEric Schrock char *str, *loc, val; 282*95efa359SEric Schrock 283*95efa359SEric Schrock if (version > TOPO_METH_STR2NVL_VERSION) 284*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 285*95efa359SEric Schrock 286*95efa359SEric Schrock if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 287*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 288*95efa359SEric Schrock 289*95efa359SEric Schrock if (strncmp(str, "svc://", 6) != 0) 290*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 291*95efa359SEric Schrock 292*95efa359SEric Schrock if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 293*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 294*95efa359SEric Schrock 295*95efa359SEric Schrock str += 6; 296*95efa359SEric Schrock if ((loc = strpbrk(str, "@/")) == NULL) 297*95efa359SEric Schrock goto malformed; 298*95efa359SEric Schrock 299*95efa359SEric Schrock if (*loc == '@') { 300*95efa359SEric Schrock /* scope */ 301*95efa359SEric Schrock *loc = '\0'; 302*95efa359SEric Schrock if (!svc_component_valid(str)) { 303*95efa359SEric Schrock *loc = '@'; 304*95efa359SEric Schrock goto malformed; 305*95efa359SEric Schrock } 306*95efa359SEric Schrock 307*95efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_AUTH_SCOPE, str) != 0) { 308*95efa359SEric Schrock *loc = '@'; 309*95efa359SEric Schrock goto nomem; 310*95efa359SEric Schrock } 311*95efa359SEric Schrock 312*95efa359SEric Schrock *loc = '@'; 313*95efa359SEric Schrock str = loc + 1; 314*95efa359SEric Schrock if ((loc = strchr(str, '/')) == NULL) 315*95efa359SEric Schrock goto malformed; 316*95efa359SEric Schrock } 317*95efa359SEric Schrock 318*95efa359SEric Schrock if (loc != str) { 319*95efa359SEric Schrock /* system-fqn */ 320*95efa359SEric Schrock *loc = '\0'; 321*95efa359SEric Schrock if (!svc_component_valid(str)) { 322*95efa359SEric Schrock *loc = '/'; 323*95efa359SEric Schrock goto malformed; 324*95efa359SEric Schrock } 325*95efa359SEric Schrock 326*95efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_AUTH_SYSTEM_FQN, 327*95efa359SEric Schrock str) != 0) { 328*95efa359SEric Schrock *loc = '/'; 329*95efa359SEric Schrock goto nomem; 330*95efa359SEric Schrock } 331*95efa359SEric Schrock 332*95efa359SEric Schrock *loc = '/'; 333*95efa359SEric Schrock } 334*95efa359SEric Schrock 335*95efa359SEric Schrock str = loc + 1; 336*95efa359SEric Schrock loc = strpbrk(str, ":@"); 337*95efa359SEric Schrock 338*95efa359SEric Schrock if (str[0] == '\0' || loc == str) 339*95efa359SEric Schrock goto malformed; 340*95efa359SEric Schrock 341*95efa359SEric Schrock if (loc != NULL) { 342*95efa359SEric Schrock val = *loc; 343*95efa359SEric Schrock *loc = '\0'; 344*95efa359SEric Schrock } 345*95efa359SEric Schrock 346*95efa359SEric Schrock /* service name */ 347*95efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_NAME, str) != 0) { 348*95efa359SEric Schrock if (loc != NULL) 349*95efa359SEric Schrock *loc = val; 350*95efa359SEric Schrock goto nomem; 351*95efa359SEric Schrock } 352*95efa359SEric Schrock 353*95efa359SEric Schrock if (loc != NULL) 354*95efa359SEric Schrock *loc = val; 355*95efa359SEric Schrock 356*95efa359SEric Schrock if (loc != NULL && *loc == ':') { 357*95efa359SEric Schrock /* instance */ 358*95efa359SEric Schrock str = loc + 1; 359*95efa359SEric Schrock if (str[0] == '\0' || str[0] == '@') 360*95efa359SEric Schrock goto malformed; 361*95efa359SEric Schrock 362*95efa359SEric Schrock loc = strchr(str, '@'); 363*95efa359SEric Schrock if (loc != NULL) 364*95efa359SEric Schrock *loc = '\0'; 365*95efa359SEric Schrock 366*95efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_INSTANCE, 367*95efa359SEric Schrock str) != 0) { 368*95efa359SEric Schrock if (loc != NULL) 369*95efa359SEric Schrock *loc = '@'; 370*95efa359SEric Schrock goto nomem; 371*95efa359SEric Schrock } 372*95efa359SEric Schrock 373*95efa359SEric Schrock if (loc != NULL) 374*95efa359SEric Schrock *loc = '@'; 375*95efa359SEric Schrock } 376*95efa359SEric Schrock 377*95efa359SEric Schrock if (loc != NULL) { 378*95efa359SEric Schrock /* contract-id */ 379*95efa359SEric Schrock assert(*loc == '@'); 380*95efa359SEric Schrock str = loc + 1; 381*95efa359SEric Schrock if (str[0] == '\0') 382*95efa359SEric Schrock goto malformed; 383*95efa359SEric Schrock 384*95efa359SEric Schrock if (nvlist_add_string(fmri, FM_FMRI_SVC_CONTRACT_ID, 385*95efa359SEric Schrock str) != 0) { 386*95efa359SEric Schrock goto nomem; 387*95efa359SEric Schrock } 388*95efa359SEric Schrock } 389*95efa359SEric Schrock 390*95efa359SEric Schrock if (nvlist_add_uint8(fmri, FM_VERSION, FM_SVC_SCHEME_VERSION) != 0 || 391*95efa359SEric Schrock nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SVC) != 0) 392*95efa359SEric Schrock goto nomem; 393*95efa359SEric Schrock 394*95efa359SEric Schrock *out = fmri; 395*95efa359SEric Schrock return (0); 396*95efa359SEric Schrock 397*95efa359SEric Schrock malformed: 398*95efa359SEric Schrock nvlist_free(fmri); 399*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 400*95efa359SEric Schrock 401*95efa359SEric Schrock nomem: 402*95efa359SEric Schrock nvlist_free(fmri); 403*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NOMEM)); 404*95efa359SEric Schrock } 405*95efa359SEric Schrock 406*95efa359SEric Schrock /* 407*95efa359SEric Schrock * This common function is shared by all consumers (present, unusable, and 408*95efa359SEric Schrock * service_state). It returns one of the FMD_SERVICE_STATE_* states, where 409*95efa359SEric Schrock * FMD_SERVICE_STATE_UNKNOWN means that the FMRI is not present. 410*95efa359SEric Schrock */ 411*95efa359SEric Schrock static int 412*95efa359SEric Schrock svc_get_state(topo_mod_t *mod, nvlist_t *fmri, boolean_t presence_only, 413*95efa359SEric Schrock int *ret) 414*95efa359SEric Schrock { 415*95efa359SEric Schrock scf_handle_t *hdl = topo_mod_getspecific(mod); 416*95efa359SEric Schrock uint8_t fmversion; 417*95efa359SEric Schrock char *instance, *name; 418*95efa359SEric Schrock scf_service_t *svc = NULL; 419*95efa359SEric Schrock scf_scope_t *scope = NULL; 420*95efa359SEric Schrock scf_instance_t *inst = NULL; 421*95efa359SEric Schrock scf_property_t *prop = NULL; 422*95efa359SEric Schrock scf_iter_t *iter = NULL; 423*95efa359SEric Schrock scf_value_t *val = NULL; 424*95efa359SEric Schrock scf_propertygroup_t *pg = NULL; 425*95efa359SEric Schrock int err, retval = 0; 426*95efa359SEric Schrock ssize_t len; 427*95efa359SEric Schrock char *state; 428*95efa359SEric Schrock 429*95efa359SEric Schrock if (nvlist_lookup_uint8(fmri, FM_VERSION, &fmversion) != 0 || 430*95efa359SEric Schrock fmversion > FM_SVC_SCHEME_VERSION || 431*95efa359SEric Schrock nvlist_lookup_string(fmri, FM_FMRI_SVC_NAME, &name) != 0) 432*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 433*95efa359SEric Schrock 434*95efa359SEric Schrock if ((svc = scf_service_create(hdl)) == NULL || 435*95efa359SEric Schrock (inst = scf_instance_create(hdl)) == NULL || 436*95efa359SEric Schrock (scope = scf_scope_create(hdl)) == NULL || 437*95efa359SEric Schrock (prop = scf_property_create(hdl)) == NULL || 438*95efa359SEric Schrock (iter = scf_iter_create(hdl)) == NULL || 439*95efa359SEric Schrock (pg = scf_pg_create(hdl)) == NULL || 440*95efa359SEric Schrock (val = scf_value_create(hdl)) == NULL) 441*95efa359SEric Schrock goto error; 442*95efa359SEric Schrock 443*95efa359SEric Schrock if (scf_handle_get_scope(hdl, SCF_SCOPE_LOCAL, scope) != 0) 444*95efa359SEric Schrock goto error; 445*95efa359SEric Schrock 446*95efa359SEric Schrock /* 447*95efa359SEric Schrock * If we fail to get the service due to _DELETED or _NOT_FOUND, then we 448*95efa359SEric Schrock * treat this as not present. 449*95efa359SEric Schrock */ 450*95efa359SEric Schrock if (scf_scope_get_service(scope, name, svc) != 0) { 451*95efa359SEric Schrock err = scf_error(); 452*95efa359SEric Schrock if (err == SCF_ERROR_NOT_FOUND || err == SCF_ERROR_DELETED) { 453*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_UNKNOWN; 454*95efa359SEric Schrock goto out; 455*95efa359SEric Schrock } else { 456*95efa359SEric Schrock goto error; 457*95efa359SEric Schrock } 458*95efa359SEric Schrock } 459*95efa359SEric Schrock 460*95efa359SEric Schrock /* 461*95efa359SEric Schrock * If there is no instance, then it is always present, and always 462*95efa359SEric Schrock * usuable. 463*95efa359SEric Schrock */ 464*95efa359SEric Schrock if (nvlist_lookup_string(fmri, FM_FMRI_SVC_INSTANCE, &instance) != 0) { 465*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_OK; 466*95efa359SEric Schrock goto out; 467*95efa359SEric Schrock } 468*95efa359SEric Schrock 469*95efa359SEric Schrock /* 470*95efa359SEric Schrock * Again, check for _DELETED or _NOT_FOUND. 471*95efa359SEric Schrock */ 472*95efa359SEric Schrock if (scf_service_get_instance(svc, instance, inst) != 0) { 473*95efa359SEric Schrock err = scf_error(); 474*95efa359SEric Schrock if (err == SCF_ERROR_NOT_FOUND || err == SCF_ERROR_DELETED) { 475*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_UNKNOWN; 476*95efa359SEric Schrock goto out; 477*95efa359SEric Schrock } else { 478*95efa359SEric Schrock goto error; 479*95efa359SEric Schrock } 480*95efa359SEric Schrock } 481*95efa359SEric Schrock 482*95efa359SEric Schrock /* 483*95efa359SEric Schrock * For presence, we are done. Otherwise, we need to get the current 484*95efa359SEric Schrock * state of the instance. 485*95efa359SEric Schrock */ 486*95efa359SEric Schrock if (presence_only) { 487*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_OK; 488*95efa359SEric Schrock goto out; 489*95efa359SEric Schrock } 490*95efa359SEric Schrock 491*95efa359SEric Schrock if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0 || 492*95efa359SEric Schrock scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) != 0 || 493*95efa359SEric Schrock scf_iter_property_values(iter, prop) != 0 || 494*95efa359SEric Schrock scf_iter_next_value(iter, val) != 1) 495*95efa359SEric Schrock goto error; 496*95efa359SEric Schrock 497*95efa359SEric Schrock if ((len = scf_value_get_astring(val, NULL, 0)) < 0) 498*95efa359SEric Schrock goto error; 499*95efa359SEric Schrock 500*95efa359SEric Schrock state = alloca(len + 1); 501*95efa359SEric Schrock if (scf_value_get_astring(val, state, len + 1) < 0) 502*95efa359SEric Schrock goto error; 503*95efa359SEric Schrock 504*95efa359SEric Schrock if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) 505*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_UNUSABLE; 506*95efa359SEric Schrock else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) 507*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_DEGRADED; 508*95efa359SEric Schrock else 509*95efa359SEric Schrock *ret = FMD_SERVICE_STATE_OK; 510*95efa359SEric Schrock goto out; 511*95efa359SEric Schrock 512*95efa359SEric Schrock error: 513*95efa359SEric Schrock retval = -1; 514*95efa359SEric Schrock out: 515*95efa359SEric Schrock scf_value_destroy(val); 516*95efa359SEric Schrock scf_pg_destroy(pg); 517*95efa359SEric Schrock scf_iter_destroy(iter); 518*95efa359SEric Schrock scf_property_destroy(prop); 519*95efa359SEric Schrock scf_instance_destroy(inst); 520*95efa359SEric Schrock scf_scope_destroy(scope); 521*95efa359SEric Schrock scf_service_destroy(svc); 522*95efa359SEric Schrock return (retval); 523*95efa359SEric Schrock } 524*95efa359SEric Schrock 525*95efa359SEric Schrock /*ARGSUSED*/ 526*95efa359SEric Schrock static int 527*95efa359SEric Schrock svc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 528*95efa359SEric Schrock nvlist_t *in, nvlist_t **out) 529*95efa359SEric Schrock { 530*95efa359SEric Schrock int state; 531*95efa359SEric Schrock 532*95efa359SEric Schrock if (version > TOPO_METH_PRESENT_VERSION) 533*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 534*95efa359SEric Schrock 535*95efa359SEric Schrock if (svc_get_state(mod, in, B_TRUE, &state) != 0) 536*95efa359SEric Schrock return (-1); 537*95efa359SEric Schrock 538*95efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 539*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 540*95efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_PRESENT_RET, 541*95efa359SEric Schrock state != FMD_SERVICE_STATE_UNKNOWN) != 0) { 542*95efa359SEric Schrock nvlist_free(*out); 543*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 544*95efa359SEric Schrock } 545*95efa359SEric Schrock 546*95efa359SEric Schrock return (0); 547*95efa359SEric Schrock } 548*95efa359SEric Schrock 549*95efa359SEric Schrock /*ARGSUSED*/ 550*95efa359SEric Schrock static int 551*95efa359SEric Schrock svc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, 552*95efa359SEric Schrock nvlist_t *in, nvlist_t **out) 553*95efa359SEric Schrock { 554*95efa359SEric Schrock int state; 555*95efa359SEric Schrock 556*95efa359SEric Schrock if (version > TOPO_METH_REPLACED_VERSION) 557*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 558*95efa359SEric Schrock 559*95efa359SEric Schrock if (svc_get_state(mod, in, B_TRUE, &state) != 0) 560*95efa359SEric Schrock return (-1); 561*95efa359SEric Schrock 562*95efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 563*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 564*95efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, 565*95efa359SEric Schrock state == FMD_SERVICE_STATE_UNKNOWN ? 566*95efa359SEric Schrock FMD_OBJ_STATE_NOT_PRESENT : FMD_OBJ_STATE_UNKNOWN) != 0) { 567*95efa359SEric Schrock nvlist_free(*out); 568*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 569*95efa359SEric Schrock } 570*95efa359SEric Schrock 571*95efa359SEric Schrock return (0); 572*95efa359SEric Schrock } 573*95efa359SEric Schrock 574*95efa359SEric Schrock /*ARGSUSED*/ 575*95efa359SEric Schrock static int 576*95efa359SEric Schrock svc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version, 577*95efa359SEric Schrock nvlist_t *in, nvlist_t **out) 578*95efa359SEric Schrock { 579*95efa359SEric Schrock int state; 580*95efa359SEric Schrock 581*95efa359SEric Schrock if (version > TOPO_METH_SERVICE_STATE_VERSION) 582*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 583*95efa359SEric Schrock 584*95efa359SEric Schrock if (svc_get_state(mod, in, B_FALSE, &state) != 0) 585*95efa359SEric Schrock return (-1); 586*95efa359SEric Schrock 587*95efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 588*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 589*95efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_SERVICE_STATE_RET, 590*95efa359SEric Schrock state) != 0) { 591*95efa359SEric Schrock nvlist_free(*out); 592*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 593*95efa359SEric Schrock } 594*95efa359SEric Schrock 595*95efa359SEric Schrock return (0); 596*95efa359SEric Schrock } 597*95efa359SEric Schrock 598*95efa359SEric Schrock /*ARGSUSED*/ 599*95efa359SEric Schrock static int 600*95efa359SEric Schrock svc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 601*95efa359SEric Schrock nvlist_t *in, nvlist_t **out) 602*95efa359SEric Schrock { 603*95efa359SEric Schrock int state; 604*95efa359SEric Schrock 605*95efa359SEric Schrock if (version > TOPO_METH_UNUSABLE_VERSION) 606*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 607*95efa359SEric Schrock 608*95efa359SEric Schrock if (svc_get_state(mod, in, B_FALSE, &state) != 0) 609*95efa359SEric Schrock return (-1); 610*95efa359SEric Schrock 611*95efa359SEric Schrock if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) 612*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 613*95efa359SEric Schrock if (nvlist_add_uint32(*out, TOPO_METH_UNUSABLE_RET, 614*95efa359SEric Schrock (state == FMD_SERVICE_STATE_UNKNOWN || 615*95efa359SEric Schrock state == FMD_SERVICE_STATE_UNUSABLE)) != 0) { 616*95efa359SEric Schrock nvlist_free(*out); 617*95efa359SEric Schrock return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 618*95efa359SEric Schrock } 619*95efa359SEric Schrock 620*95efa359SEric Schrock return (0); 621*95efa359SEric Schrock } 622