1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <strings.h>
  28 #include <stdlib.h>
  29 #include <netdir.h>
  30 #include <errno.h>
  31 #include <alloca.h>
  32 #include <locale.h>
  33 #include <uuid/uuid.h>
  34 
  35 #include <sys/fm/protocol.h>
  36 #include <fmd_adm_impl.h>
  37 #include <fmd_rpc_adm.h>
  38 
  39 static const uint_t _fmd_adm_bufsize = 128 * 1024;
  40 static const char _url_fallback[] = "http://illumos.org/msg/";
  41 
  42 fmd_adm_t *
  43 fmd_adm_open(const char *host, uint32_t prog, int version)
  44 {
  45         fmd_adm_t *ap;
  46         CLIENT *c;
  47         rpcvers_t v;
  48 
  49         if (version != FMD_ADM_VERSION) {
  50                 errno = ENOTSUP;
  51                 return (NULL);
  52         }
  53 
  54         if (host == NULL)
  55                 host = HOST_SELF;
  56 
  57         if (prog == FMD_ADM_PROGRAM)
  58                 prog = FMD_ADM;
  59 
  60         if ((ap = malloc(sizeof (fmd_adm_t))) == NULL)
  61                 return (NULL);
  62 
  63         if (strcmp(host, HOST_SELF) == 0) {
  64                 c = clnt_door_create(prog, FMD_ADM_VERSION_1, _fmd_adm_bufsize);
  65                 ap->adm_maxretries = 1;
  66         } else {
  67                 c = clnt_create_vers(host, prog, &v,
  68                     FMD_ADM_VERSION_1, FMD_ADM_VERSION_1, NULL);
  69                 ap->adm_maxretries = 0;
  70         }
  71 
  72         if (c == NULL) {
  73                 errno = EPROTO;
  74                 free(ap);
  75                 return (NULL);
  76         }
  77 
  78         ap->adm_prog = prog;
  79         ap->adm_clnt = c;
  80         ap->adm_version = version;
  81         ap->adm_svcerr = 0;
  82         ap->adm_errno = 0;
  83 
  84         return (ap);
  85 }
  86 
  87 void
  88 fmd_adm_close(fmd_adm_t *ap)
  89 {
  90         if (ap == NULL)
  91                 return; /* permit NULL to simply caller code */
  92 
  93         clnt_destroy(ap->adm_clnt);
  94         free(ap);
  95 }
  96 
  97 static const char *
  98 fmd_adm_svc_errmsg(enum fmd_adm_error err)
  99 {
 100         switch (err) {
 101         case FMD_ADM_ERR_NOMEM:
 102                 return ("unable to perform request due to allocation failure");
 103         case FMD_ADM_ERR_PERM:
 104                 return ("operation requires additional privilege");
 105         case FMD_ADM_ERR_MODSRCH:
 106                 return ("specified module is not loaded in fault manager");
 107         case FMD_ADM_ERR_MODBUSY:
 108                 return ("module is in use and cannot be unloaded");
 109         case FMD_ADM_ERR_MODFAIL:
 110                 return ("module failed and can no longer export statistics");
 111         case FMD_ADM_ERR_MODNOENT:
 112                 return ("file missing or cannot be accessed by fault manager");
 113         case FMD_ADM_ERR_MODEXIST:
 114                 return ("module using same name is already loaded");
 115         case FMD_ADM_ERR_MODINIT:
 116                 return ("module failed to initialize (consult fmd(1M) log)");
 117         case FMD_ADM_ERR_MODLOAD:
 118                 return ("module failed to load (consult fmd(1M) log)");
 119         case FMD_ADM_ERR_RSRCSRCH:
 120                 return ("specified resource is not cached by fault manager");
 121         case FMD_ADM_ERR_RSRCNOTF:
 122                 return ("specified resource is not known to be faulty");
 123         case FMD_ADM_ERR_SERDSRCH:
 124                 return ("specified serd engine not present in module");
 125         case FMD_ADM_ERR_SERDFIRED:
 126                 return ("specified serd engine has already fired");
 127         case FMD_ADM_ERR_ROTSRCH:
 128                 return ("invalid log file name");
 129         case FMD_ADM_ERR_ROTFAIL:
 130                 return ("failed to rotate log file (consult fmd(1M) log)");
 131         case FMD_ADM_ERR_ROTBUSY:
 132                 return ("log file is too busy to rotate (try again later)");
 133         case FMD_ADM_ERR_CASESRCH:
 134                 return ("specified UUID is invalid or has been repaired");
 135         case FMD_ADM_ERR_CASEOPEN:
 136                 return ("specified UUID is still being diagnosed");
 137         case FMD_ADM_ERR_XPRTSRCH:
 138                 return ("specified transport ID is invalid or has been closed");
 139         case FMD_ADM_ERR_CASEXPRT:
 140                 return ("specified UUID is owned by a different fault manager");
 141         case FMD_ADM_ERR_RSRCNOTR:
 142                 return ("specified resource has not been replaced");
 143         default:
 144                 return ("unknown fault manager error");
 145         }
 146 }
 147 
 148 const char *
 149 fmd_adm_errmsg(fmd_adm_t *ap)
 150 {
 151         if (ap == NULL) {
 152                 switch (errno) {
 153                 case ENOTSUP:
 154                         return ("client requires newer libfmd_adm version");
 155                 case EPROTO:
 156                         return (clnt_spcreateerror("failed to connect to fmd"));
 157                 }
 158         }
 159 
 160         switch (ap ? ap->adm_errno : errno) {
 161         case EPROTO:
 162                 return (clnt_sperror(ap->adm_clnt, "rpc call failed"));
 163         case EREMOTE:
 164                 return (fmd_adm_svc_errmsg(ap->adm_svcerr));
 165         default:
 166                 return (strerror(ap->adm_errno));
 167         }
 168 }
 169 
 170 static int
 171 fmd_adm_set_svcerr(fmd_adm_t *ap, enum fmd_adm_error err)
 172 {
 173         if (err != 0) {
 174                 ap->adm_svcerr = err;
 175                 ap->adm_errno = EREMOTE;
 176                 return (-1);
 177         } else {
 178                 ap->adm_svcerr = err;
 179                 ap->adm_errno = 0;
 180                 return (0);
 181         }
 182 }
 183 
 184 static int
 185 fmd_adm_set_errno(fmd_adm_t *ap, int err)
 186 {
 187         ap->adm_errno = err;
 188         errno = err;
 189         return (-1);
 190 }
 191 
 192 static int
 193 fmd_adm_stats_cmp(const void *lp, const void *rp)
 194 {
 195         return (strcmp(((fmd_stat_t *)lp)->fmds_name,
 196             ((fmd_stat_t *)rp)->fmds_name));
 197 }
 198 
 199 /*
 200  * If the server (fmd) is restarted, this will cause all future door calls to
 201  * fail.  Unfortunately, once the server comes back up, we have no way of
 202  * reestablishing the connection.  To get around this, if the error indicates
 203  * that the RPC call failed, we reopen the client handle and try again.  For
 204  * simplicity we only deal with the door case, as it's unclear whether the
 205  * remote case suffers from the same pathology.
 206  */
 207 boolean_t
 208 fmd_adm_retry(fmd_adm_t *ap, enum clnt_stat cs, uint_t *retries)
 209 {
 210         CLIENT *c;
 211         struct rpc_err err;
 212 
 213         if (cs == RPC_SUCCESS || *retries == ap->adm_maxretries)
 214                 return (B_FALSE);
 215 
 216         clnt_geterr(ap->adm_clnt, &err);
 217         if (err.re_status != RPC_CANTSEND)
 218                 return (B_FALSE);
 219 
 220         if ((c = clnt_door_create(ap->adm_prog, FMD_ADM_VERSION_1,
 221             _fmd_adm_bufsize)) == NULL)
 222                 return (B_FALSE);
 223 
 224         (*retries)++;
 225 
 226         clnt_destroy(ap->adm_clnt);
 227         ap->adm_clnt = c;
 228 
 229         return (B_TRUE);
 230 }
 231 
 232 int
 233 fmd_adm_stats_read(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp)
 234 {
 235         struct fmd_rpc_modstat rms;
 236         enum clnt_stat cs;
 237         uint_t retries = 0;
 238 
 239         if (sp == NULL)
 240                 return (fmd_adm_set_errno(ap, EINVAL));
 241 
 242         bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
 243 
 244         do {
 245                 if (name != NULL)
 246                         cs = fmd_adm_modcstat_1((char *)name, &rms,
 247                             ap->adm_clnt);
 248                 else
 249                         cs = fmd_adm_modgstat_1(&rms, ap->adm_clnt);
 250         } while (fmd_adm_retry(ap, cs, &retries));
 251 
 252         if (cs != RPC_SUCCESS)
 253                 return (fmd_adm_set_errno(ap, EPROTO));
 254 
 255         if (rms.rms_err != 0) {
 256                 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
 257                 return (fmd_adm_set_svcerr(ap, rms.rms_err));
 258         }
 259 
 260         sp->ams_buf = rms.rms_buf.rms_buf_val;
 261         sp->ams_len = rms.rms_buf.rms_buf_len;
 262 
 263         if (sp->ams_len != 0) {
 264                 qsort(sp->ams_buf, sp->ams_len,
 265                     sizeof (fmd_stat_t), fmd_adm_stats_cmp);
 266         }
 267 
 268         return (0);
 269 }
 270 
 271 int
 272 fmd_adm_stats_free(fmd_adm_t *ap, fmd_adm_stats_t *sp)
 273 {
 274         struct fmd_rpc_modstat rms;
 275 
 276         if (sp == NULL)
 277                 return (fmd_adm_set_errno(ap, EINVAL));
 278 
 279         rms.rms_buf.rms_buf_val = sp->ams_buf;
 280         rms.rms_buf.rms_buf_len = sp->ams_len;
 281         rms.rms_err = 0;
 282 
 283         xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
 284         bzero(sp, sizeof (fmd_adm_stats_t));
 285 
 286         return (0);
 287 }
 288 
 289 static int
 290 fmd_adm_module_cmp(const void *lp, const void *rp)
 291 {
 292         return (strcmp((*(struct fmd_rpc_modinfo **)lp)->rmi_name,
 293             (*(struct fmd_rpc_modinfo **)rp)->rmi_name));
 294 }
 295 
 296 int
 297 fmd_adm_module_iter(fmd_adm_t *ap, fmd_adm_module_f *func, void *arg)
 298 {
 299         struct fmd_rpc_modinfo *rmi, **rms, **rmp;
 300         struct fmd_rpc_modlist rml;
 301         fmd_adm_modinfo_t ami;
 302         enum clnt_stat cs;
 303         uint_t retries = 0;
 304 
 305         bzero(&rml, sizeof (rml)); /* tell xdr to allocate memory for us */
 306 
 307         do {
 308                 cs = fmd_adm_modinfo_1(&rml, ap->adm_clnt);
 309         } while (fmd_adm_retry(ap, cs, &retries));
 310 
 311         if (cs != RPC_SUCCESS)
 312                 return (fmd_adm_set_errno(ap, EPROTO));
 313 
 314         if (rml.rml_err != 0 || rml.rml_len == 0) {
 315                 xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
 316                 return (fmd_adm_set_svcerr(ap, rml.rml_err));
 317         }
 318 
 319         if ((rms = rmp = malloc(sizeof (void *) * rml.rml_len)) == NULL) {
 320                 xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
 321                 return (fmd_adm_set_errno(ap, EAGAIN));
 322         }
 323 
 324         for (rmi = rml.rml_list; rmi != NULL; rmi = rmi->rmi_next)
 325                 *rmp++ = rmi; /* store copy of pointer in array for sorting */
 326 
 327         qsort(rms, rml.rml_len, sizeof (void *), fmd_adm_module_cmp);
 328 
 329         for (rmp = rms; rmp < rms + rml.rml_len; rmp++) {
 330                 rmi = *rmp;
 331 
 332                 ami.ami_name = rmi->rmi_name;
 333                 ami.ami_desc = rmi->rmi_desc;
 334                 ami.ami_vers = rmi->rmi_vers;
 335                 ami.ami_flags = 0;
 336 
 337                 if (rmi->rmi_faulty)
 338                         ami.ami_flags |= FMD_ADM_MOD_FAILED;
 339 
 340                 if (func(&ami, arg) != 0)
 341                         break;
 342         }
 343 
 344         free(rms);
 345         xdr_free(xdr_fmd_rpc_modlist, (char *)&rml);
 346         return (0);
 347 }
 348 
 349 int
 350 fmd_adm_module_load(fmd_adm_t *ap, const char *path)
 351 {
 352         char *str = (char *)path;
 353         int err;
 354         enum clnt_stat cs;
 355         uint_t retries = 0;
 356 
 357         if (path == NULL || path[0] != '/')
 358                 return (fmd_adm_set_errno(ap, EINVAL));
 359 
 360         do {
 361                 cs = fmd_adm_modload_1(str, &err, ap->adm_clnt);
 362         } while (fmd_adm_retry(ap, cs, &retries));
 363 
 364         if (cs != RPC_SUCCESS)
 365                 return (fmd_adm_set_errno(ap, EPROTO));
 366 
 367         return (fmd_adm_set_svcerr(ap, err));
 368 }
 369 
 370 int
 371 fmd_adm_module_unload(fmd_adm_t *ap, const char *name)
 372 {
 373         char *str = (char *)name;
 374         int err;
 375         enum clnt_stat cs;
 376         uint_t retries = 0;
 377 
 378         if (name == NULL || strchr(name, '/') != NULL)
 379                 return (fmd_adm_set_errno(ap, EINVAL));
 380 
 381         do {
 382                 cs = fmd_adm_modunload_1(str, &err, ap->adm_clnt);
 383         } while (fmd_adm_retry(ap, cs, &retries));
 384 
 385         if (cs != RPC_SUCCESS)
 386                 return (fmd_adm_set_errno(ap, EPROTO));
 387 
 388         return (fmd_adm_set_svcerr(ap, err));
 389 }
 390 
 391 int
 392 fmd_adm_module_reset(fmd_adm_t *ap, const char *name)
 393 {
 394         char *str = (char *)name;
 395         int err;
 396         enum clnt_stat cs;
 397         uint_t retries = 0;
 398 
 399         if (name == NULL || strchr(name, '/') != NULL)
 400                 return (fmd_adm_set_errno(ap, EINVAL));
 401 
 402         do {
 403                 cs = fmd_adm_modreset_1(str, &err, ap->adm_clnt);
 404         } while (fmd_adm_retry(ap, cs, &retries));
 405 
 406         if (cs != RPC_SUCCESS)
 407                 return (fmd_adm_set_errno(ap, EPROTO));
 408 
 409         return (fmd_adm_set_svcerr(ap, err));
 410 }
 411 
 412 int
 413 fmd_adm_module_gc(fmd_adm_t *ap, const char *name)
 414 {
 415         char *str = (char *)name;
 416         int err;
 417         enum clnt_stat cs;
 418         uint_t retries = 0;
 419 
 420         if (name == NULL || strchr(name, '/') != NULL)
 421                 return (fmd_adm_set_errno(ap, EINVAL));
 422 
 423         do {
 424                 cs = fmd_adm_modgc_1(str, &err, ap->adm_clnt);
 425         } while (fmd_adm_retry(ap, cs, &retries));
 426 
 427         if (cs != RPC_SUCCESS)
 428                 return (fmd_adm_set_errno(ap, EPROTO));
 429 
 430         return (fmd_adm_set_svcerr(ap, err));
 431 }
 432 
 433 int
 434 fmd_adm_module_stats(fmd_adm_t *ap, const char *name, fmd_adm_stats_t *sp)
 435 {
 436         struct fmd_rpc_modstat rms;
 437         enum clnt_stat cs;
 438         uint_t retries = 0;
 439 
 440         if (name == NULL || sp == NULL)
 441                 return (fmd_adm_set_errno(ap, EINVAL));
 442 
 443         bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
 444 
 445         do {
 446                 cs = fmd_adm_moddstat_1((char *)name, &rms, ap->adm_clnt);
 447         } while (fmd_adm_retry(ap, cs, &retries));
 448 
 449         if (cs != RPC_SUCCESS)
 450                 return (fmd_adm_set_errno(ap, EPROTO));
 451 
 452         if (rms.rms_err != 0) {
 453                 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
 454                 return (fmd_adm_set_svcerr(ap, rms.rms_err));
 455         }
 456 
 457         sp->ams_buf = rms.rms_buf.rms_buf_val;
 458         sp->ams_len = rms.rms_buf.rms_buf_len;
 459 
 460         return (0);
 461 }
 462 
 463 int
 464 fmd_adm_rsrc_count(fmd_adm_t *ap, int all, uint32_t *rcp)
 465 {
 466         struct fmd_rpc_rsrclist rrl;
 467         enum clnt_stat cs;
 468         uint_t retries = 0;
 469 
 470         if (rcp == NULL)
 471                 return (fmd_adm_set_errno(ap, EINVAL));
 472 
 473         bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */
 474 
 475         do {
 476                 cs = fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt);
 477         } while (fmd_adm_retry(ap, cs, &retries));
 478 
 479         if (cs != RPC_SUCCESS)
 480                 return (fmd_adm_set_errno(ap, EPROTO));
 481 
 482         if (rrl.rrl_err != 0) {
 483                 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 484                 return (fmd_adm_set_svcerr(ap, rrl.rrl_err));
 485         }
 486 
 487         *rcp = rrl.rrl_cnt;
 488         xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 489         return (0);
 490 }
 491 
 492 static int
 493 fmd_adm_rsrc_cmp(const void *lp, const void *rp)
 494 {
 495         return (strcmp(*(char **)lp, *(char **)rp));
 496 }
 497 
 498 int
 499 fmd_adm_rsrc_iter(fmd_adm_t *ap, int all, fmd_adm_rsrc_f *func, void *arg)
 500 {
 501         struct fmd_rpc_rsrclist rrl;
 502         struct fmd_rpc_rsrcinfo rri;
 503         fmd_adm_rsrcinfo_t ari;
 504         char **fmris, *p;
 505         int i, rv;
 506         enum clnt_stat cs;
 507         uint_t retries = 0;
 508 
 509         bzero(&rrl, sizeof (rrl)); /* tell xdr to allocate memory for us */
 510 
 511         do {
 512                 cs = fmd_adm_rsrclist_1(all, &rrl, ap->adm_clnt);
 513         } while (fmd_adm_retry(ap, cs, &retries));
 514 
 515         if (cs != RPC_SUCCESS)
 516                 return (fmd_adm_set_errno(ap, EPROTO));
 517 
 518         if (rrl.rrl_err != 0) {
 519                 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 520                 return (fmd_adm_set_svcerr(ap, rrl.rrl_err));
 521         }
 522 
 523         if ((fmris = malloc(sizeof (char *) * rrl.rrl_cnt)) == NULL) {
 524                 xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 525                 return (fmd_adm_set_errno(ap, EAGAIN));
 526         }
 527 
 528         /*
 529          * The fmd_adm_rsrclist_1 request returns an opaque XDR buffer that is
 530          * a string table of FMRIs (e.g. "fmriA\0fmriB\0...") where rrl_cnt is
 531          * the number of strings in the table and rrl_buf_val is its address.
 532          * We construct an array of pointers into the string table and sort it.
 533          */
 534         p = rrl.rrl_buf.rrl_buf_val;
 535 
 536         for (i = 0; i < rrl.rrl_cnt; i++, p += strlen(p) + 1)
 537                 fmris[i] = p; /* store fmri pointer in array for sorting */
 538 
 539         qsort(fmris, rrl.rrl_cnt, sizeof (char *), fmd_adm_rsrc_cmp);
 540 
 541         /*
 542          * For each FMRI in the resource cache snapshot, use fmd_adm_rsrcinfo_1
 543          * to get more information and the invoke the callback function.  If
 544          * FMD_ADM_ERR_RSRCSRCH is returned, the FMRI has been purged from the
 545          * cache since our snapshot: this error is therefore silently ignored.
 546          */
 547         for (i = 0; i < rrl.rrl_cnt; i++) {
 548                 bzero(&rri, sizeof (rri));
 549 
 550                 retries = 0;
 551                 do {
 552                         cs = fmd_adm_rsrcinfo_1(fmris[i], &rri, ap->adm_clnt);
 553                 } while (fmd_adm_retry(ap, cs, &retries));
 554 
 555                 if (cs != RPC_SUCCESS) {
 556                         free(fmris);
 557                         xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 558                         return (fmd_adm_set_errno(ap, EPROTO));
 559                 }
 560 
 561                 if (rri.rri_err != 0 && rri.rri_err != FMD_ADM_ERR_RSRCSRCH) {
 562                         xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
 563                         free(fmris);
 564                         xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 565                         return (fmd_adm_set_svcerr(ap, rri.rri_err));
 566                 }
 567 
 568                 if (rri.rri_err == FMD_ADM_ERR_RSRCSRCH) {
 569                         xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
 570                         continue;
 571                 }
 572 
 573                 ari.ari_fmri = rri.rri_fmri;
 574                 ari.ari_uuid = rri.rri_uuid;
 575                 ari.ari_case = rri.rri_case;
 576                 ari.ari_flags = 0;
 577 
 578                 if (rri.rri_faulty)
 579                         ari.ari_flags |= FMD_ADM_RSRC_FAULTY;
 580                 if (rri.rri_unusable)
 581                         ari.ari_flags |= FMD_ADM_RSRC_UNUSABLE;
 582                 if (rri.rri_invisible)
 583                         ari.ari_flags |= FMD_ADM_RSRC_INVISIBLE;
 584 
 585                 rv = func(&ari, arg);
 586                 xdr_free(xdr_fmd_rpc_rsrcinfo, (char *)&rri);
 587 
 588                 if (rv != 0)
 589                         break;
 590         }
 591 
 592         free(fmris);
 593         xdr_free(xdr_fmd_rpc_rsrclist, (char *)&rrl);
 594         return (0);
 595 }
 596 
 597 int
 598 fmd_adm_rsrc_flush(fmd_adm_t *ap, const char *fmri)
 599 {
 600         char *str = (char *)fmri;
 601         int err;
 602         enum clnt_stat cs;
 603         uint_t retries = 0;
 604 
 605         if (fmri == NULL)
 606                 return (fmd_adm_set_errno(ap, EINVAL));
 607 
 608         do {
 609                 cs = fmd_adm_rsrcflush_1(str, &err, ap->adm_clnt);
 610         } while (fmd_adm_retry(ap, cs, &retries));
 611 
 612         if (cs != RPC_SUCCESS)
 613                 return (fmd_adm_set_errno(ap, EPROTO));
 614 
 615         return (fmd_adm_set_svcerr(ap, err));
 616 }
 617 
 618 int
 619 fmd_adm_rsrc_repaired(fmd_adm_t *ap, const char *fmri)
 620 {
 621         char *str = (char *)fmri;
 622         int err;
 623         enum clnt_stat cs;
 624         uint_t retries = 0;
 625 
 626         if (fmri == NULL)
 627                 return (fmd_adm_set_errno(ap, EINVAL));
 628 
 629         do {
 630                 cs = fmd_adm_rsrcrepaired_1(str, &err, ap->adm_clnt);
 631         } while (fmd_adm_retry(ap, cs, &retries));
 632 
 633         if (cs != RPC_SUCCESS)
 634                 return (fmd_adm_set_errno(ap, EPROTO));
 635 
 636         return (fmd_adm_set_svcerr(ap, err));
 637 }
 638 
 639 int
 640 fmd_adm_rsrc_replaced(fmd_adm_t *ap, const char *fmri)
 641 {
 642         char *str = (char *)fmri;
 643         int err;
 644         enum clnt_stat cs;
 645         uint_t retries = 0;
 646 
 647         if (fmri == NULL)
 648                 return (fmd_adm_set_errno(ap, EINVAL));
 649 
 650         do {
 651                 cs = fmd_adm_rsrcreplaced_1(str, &err, ap->adm_clnt);
 652         } while (fmd_adm_retry(ap, cs, &retries));
 653 
 654         if (cs != RPC_SUCCESS)
 655                 return (fmd_adm_set_errno(ap, EPROTO));
 656 
 657         return (fmd_adm_set_svcerr(ap, err));
 658 }
 659 
 660 int
 661 fmd_adm_rsrc_acquit(fmd_adm_t *ap, const char *fmri, const char *uuid)
 662 {
 663         char *str = (char *)fmri;
 664         char *str2 = (char *)uuid;
 665         int err;
 666         enum clnt_stat cs;
 667         uint_t retries = 0;
 668 
 669         if (fmri == NULL)
 670                 return (fmd_adm_set_errno(ap, EINVAL));
 671 
 672         do {
 673                 cs = fmd_adm_rsrcacquit_1(str, str2, &err, ap->adm_clnt);
 674         } while (fmd_adm_retry(ap, cs, &retries));
 675 
 676         if (cs != RPC_SUCCESS)
 677                 return (fmd_adm_set_errno(ap, EPROTO));
 678 
 679         return (fmd_adm_set_svcerr(ap, err));
 680 }
 681 
 682 int
 683 fmd_adm_case_repair(fmd_adm_t *ap, const char *uuid)
 684 {
 685         char *str = (char *)uuid;
 686         int err;
 687         enum clnt_stat cs;
 688         uint_t retries = 0;
 689 
 690         if (uuid == NULL)
 691                 return (fmd_adm_set_errno(ap, EINVAL));
 692 
 693         do {
 694                 cs = fmd_adm_caserepair_1(str, &err, ap->adm_clnt);
 695         } while (fmd_adm_retry(ap, cs, &retries));
 696 
 697         if (cs != RPC_SUCCESS)
 698                 return (fmd_adm_set_errno(ap, EPROTO));
 699 
 700         return (fmd_adm_set_svcerr(ap, err));
 701 }
 702 
 703 int
 704 fmd_adm_case_acquit(fmd_adm_t *ap, const char *uuid)
 705 {
 706         char *str = (char *)uuid;
 707         int err;
 708         enum clnt_stat cs;
 709         uint_t retries = 0;
 710 
 711         if (uuid == NULL)
 712                 return (fmd_adm_set_errno(ap, EINVAL));
 713 
 714         do {
 715                 cs = fmd_adm_caseacquit_1(str, &err, ap->adm_clnt);
 716         } while (fmd_adm_retry(ap, cs, &retries));
 717 
 718         if (cs != RPC_SUCCESS)
 719                 return (fmd_adm_set_errno(ap, EPROTO));
 720 
 721         return (fmd_adm_set_svcerr(ap, err));
 722 }
 723 
 724 static int
 725 fmd_adm_case_cmp(const void *lp, const void *rp)
 726 {
 727         return (strcmp(*(char **)lp, *(char **)rp));
 728 }
 729 
 730 static int
 731 fmd_adm_case_one(fmd_adm_caseinfo_t *acp, const char *url_token,
 732     fmd_adm_case_f *func, void *arg)
 733 {
 734         char *p, *urlcode, *dict, *olang;
 735         const char *url;
 736         size_t  len;
 737 
 738         if ((p = strchr(acp->aci_code, '-')) == NULL ||
 739             p == acp->aci_code) {
 740                 acp->aci_url = NULL;
 741         } else {
 742                 dict = alloca((size_t)(p - acp->aci_code) + 1);
 743                 (void) strncpy(dict, acp->aci_code,
 744                     (size_t)(p - acp->aci_code));
 745                 dict[(size_t)(p - acp->aci_code)] = '\0';
 746 
 747                 /*
 748                  * If we're given a token to use in looking up the URL, try
 749                  * to use it.  Otherwise, or if we don't find it that way,
 750                  * use the fallback.
 751                  */
 752                 if (url_token == NULL) {
 753                         url = _url_fallback;
 754                 } else if ((url = dgettext(dict, url_token)) == url_token) {
 755                         /*
 756                          * We didn't find a translation in the
 757                          * dictionary for the current language.  Fall
 758                          * back to C and try again.
 759                          */
 760                         olang = setlocale(LC_MESSAGES, NULL);
 761                         (void) setlocale(LC_MESSAGES, "C");
 762                         if ((url = dgettext(dict, url_token)) == url_token)
 763                                 url = _url_fallback;
 764                         (void) setlocale(LC_MESSAGES, olang);
 765                 }
 766                 len = strlen(url);
 767                 if (url[len - 1] == '/') {
 768                         len += strlen(acp->aci_code) + 1;
 769                         urlcode = alloca(len);
 770                         (void) snprintf(urlcode, len, "%s%s", url,
 771                             acp->aci_code);
 772                 } else {
 773                         urlcode = (char *)url;
 774                 }
 775                 acp->aci_url = urlcode;
 776         }
 777 
 778         return (func(acp, arg));
 779 }
 780 
 781 /*
 782  * Our approach to cases is the same as for resources: we first obtain a
 783  * list of UUIDs, sort them, then obtain the case information for each.
 784  */
 785 int
 786 fmd_adm_case_iter(fmd_adm_t *ap, const char *url_token, fmd_adm_case_f *func,
 787     void *arg)
 788 {
 789         struct fmd_rpc_caselist rcl;
 790         struct fmd_rpc_caseinfo rci;
 791         fmd_adm_caseinfo_t aci;
 792         char **uuids, *p;
 793         int i, rv;
 794         enum clnt_stat cs;
 795         uint_t retries = 0;
 796 
 797         bzero(&rcl, sizeof (rcl)); /* tell xdr to allocate memory for us */
 798 
 799         do {
 800                 cs = fmd_adm_caselist_1(&rcl, ap->adm_clnt);
 801         } while (fmd_adm_retry(ap, cs, &retries));
 802 
 803         if (cs != RPC_SUCCESS)
 804                 return (fmd_adm_set_errno(ap, EPROTO));
 805 
 806         if (rcl.rcl_err != 0) {
 807                 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 808                 return (fmd_adm_set_svcerr(ap, rcl.rcl_err));
 809         }
 810 
 811         if ((uuids = malloc(sizeof (char *) * rcl.rcl_cnt)) == NULL) {
 812                 xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 813                 return (fmd_adm_set_errno(ap, EAGAIN));
 814         }
 815 
 816         p = rcl.rcl_buf.rcl_buf_val;
 817 
 818         for (i = 0; i < rcl.rcl_cnt; i++, p += strlen(p) + 1)
 819                 uuids[i] = p;
 820 
 821         qsort(uuids, rcl.rcl_cnt, sizeof (char *), fmd_adm_case_cmp);
 822 
 823         for (i = 0; i < rcl.rcl_cnt; i++) {
 824                 bzero(&rci, sizeof (rci));
 825 
 826                 retries = 0;
 827                 do {
 828                         cs = fmd_adm_caseinfo_1(uuids[i], &rci, ap->adm_clnt);
 829                 } while (fmd_adm_retry(ap, cs, &retries));
 830 
 831                 if (cs != RPC_SUCCESS) {
 832                         free(uuids);
 833                         xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 834                         return (fmd_adm_set_errno(ap, EPROTO));
 835                 }
 836 
 837                 if (rci.rci_err != 0 && rci.rci_err != FMD_ADM_ERR_CASESRCH) {
 838                         xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
 839                         free(uuids);
 840                         xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 841                         return (fmd_adm_set_svcerr(ap, rci.rci_err));
 842                 }
 843 
 844                 if (rci.rci_err == FMD_ADM_ERR_CASESRCH) {
 845                         xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
 846                         continue;
 847                 }
 848 
 849                 bzero(&aci, sizeof (aci));
 850 
 851                 if ((rv = nvlist_unpack(rci.rci_evbuf.rci_evbuf_val,
 852                     rci.rci_evbuf.rci_evbuf_len, &aci.aci_event, 0)) != 0) {
 853                         xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
 854                         free(uuids);
 855                         xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 856                         return (fmd_adm_set_errno(ap, rv));
 857                 }
 858 
 859                 if ((rv = nvlist_lookup_string(aci.aci_event, FM_SUSPECT_UUID,
 860                     (char **)&aci.aci_uuid)) != 0) {
 861                         xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
 862                         free(uuids);
 863                         xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 864                         nvlist_free(aci.aci_event);
 865                         return (fmd_adm_set_errno(ap, rv));
 866                 }
 867                 if ((rv = nvlist_lookup_string(aci.aci_event,
 868                     FM_SUSPECT_DIAG_CODE, (char **)&aci.aci_code)) != 0) {
 869                         xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
 870                         free(uuids);
 871                         xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 872                         nvlist_free(aci.aci_event);
 873                         return (fmd_adm_set_errno(ap, rv));
 874                 }
 875 
 876                 rv = fmd_adm_case_one(&aci, url_token, func, arg);
 877 
 878                 xdr_free(xdr_fmd_rpc_caseinfo, (char *)&rci);
 879                 nvlist_free(aci.aci_event);
 880 
 881                 if (rv != 0)
 882                         break;
 883         }
 884 
 885         free(uuids);
 886         xdr_free(xdr_fmd_rpc_caselist, (char *)&rcl);
 887         return (0);
 888 }
 889 
 890 static int
 891 fmd_adm_serd_cmp(const void *lp, const void *rp)
 892 {
 893         return (strcmp(*(char **)lp, *(char **)rp));
 894 }
 895 
 896 int
 897 fmd_adm_serd_iter(fmd_adm_t *ap, const char *name,
 898     fmd_adm_serd_f *func, void *arg)
 899 {
 900         struct fmd_rpc_serdlist rsl;
 901         struct fmd_rpc_serdinfo rsi;
 902         char **serds, *p;
 903         fmd_adm_serdinfo_t asi;
 904         enum clnt_stat cs;
 905         uint_t retries = 0;
 906         int i, rv;
 907 
 908         bzero(&rsl, sizeof (rsl)); /* tell xdr to allocate memory for us */
 909 
 910         do {
 911                 cs = fmd_adm_serdlist_1((char *)name, &rsl, ap->adm_clnt);
 912         } while (fmd_adm_retry(ap, cs, &retries));
 913 
 914         if (cs != RPC_SUCCESS)
 915                 return (fmd_adm_set_errno(ap, EPROTO));
 916 
 917         if (rsl.rsl_err != 0 || rsl.rsl_len == 0) {
 918                 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
 919                 return (fmd_adm_set_svcerr(ap, rsl.rsl_err));
 920         }
 921 
 922         if ((serds = malloc(sizeof (char *) * rsl.rsl_cnt)) == NULL) {
 923                 xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
 924                 return (fmd_adm_set_errno(ap, EAGAIN));
 925         }
 926 
 927         p = rsl.rsl_buf.rsl_buf_val;
 928 
 929         for (i = 0; i < rsl.rsl_cnt; i++, p += strlen(p) + 1)
 930                 serds[i] = p;
 931 
 932         qsort(serds, rsl.rsl_cnt, sizeof (char *), fmd_adm_serd_cmp);
 933 
 934         for (i = 0; i < rsl.rsl_cnt; i++) {
 935                 bzero(&rsi, sizeof (rsi));
 936 
 937                 retries = 0;
 938                 do {
 939                         cs = fmd_adm_serdinfo_1((char *)name, serds[i], &rsi,
 940                             ap->adm_clnt);
 941                 } while (fmd_adm_retry(ap, cs, &retries));
 942 
 943                 if (cs != RPC_SUCCESS) {
 944                         free(serds);
 945                         xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
 946                         return (fmd_adm_set_errno(ap, EPROTO));
 947                 }
 948 
 949                 if (rsi.rsi_err != 0 && rsi.rsi_err != FMD_ADM_ERR_SERDSRCH) {
 950                         free(serds);
 951                         xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi);
 952                         xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
 953                         return (fmd_adm_set_svcerr(ap, rsi.rsi_err));
 954                 }
 955 
 956                 if (rsi.rsi_err == FMD_ADM_ERR_SERDSRCH) {
 957                         xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi);
 958                         continue;
 959                 }
 960 
 961                 bzero(&asi, sizeof (asi));
 962 
 963                 asi.asi_name = rsi.rsi_name;
 964                 asi.asi_delta = rsi.rsi_delta;
 965                 asi.asi_n = rsi.rsi_n;
 966                 asi.asi_t = rsi.rsi_t;
 967                 asi.asi_count = rsi.rsi_count;
 968                 asi.asi_flags = 0;
 969 
 970                 if (rsi.rsi_fired)
 971                         asi.asi_flags |= FMD_ADM_SERD_FIRED;
 972 
 973                 rv = func(&asi, arg);
 974 
 975                 xdr_free(xdr_fmd_rpc_serdinfo, (char *)&rsi);
 976 
 977                 if (rv != 0)
 978                         break;
 979         }
 980 
 981         free(serds);
 982         xdr_free(xdr_fmd_rpc_serdlist, (char *)&rsl);
 983         return (0);
 984 }
 985 
 986 int
 987 fmd_adm_serd_reset(fmd_adm_t *ap, const char *mod, const char *name)
 988 {
 989         char *s1 = (char *)mod, *s2 = (char *)name;
 990         int err;
 991         enum clnt_stat cs;
 992         uint_t retries = 0;
 993 
 994         if (mod == NULL || name == NULL || strchr(mod, '/') != NULL)
 995                 return (fmd_adm_set_errno(ap, EINVAL));
 996 
 997         do {
 998                 cs = fmd_adm_serdreset_1(s1, s2, &err, ap->adm_clnt);
 999         } while (fmd_adm_retry(ap, cs, &retries));
1000 
1001         if (cs != RPC_SUCCESS)
1002                 return (fmd_adm_set_errno(ap, EPROTO));
1003 
1004         return (fmd_adm_set_svcerr(ap, err));
1005 }
1006 
1007 int
1008 fmd_adm_xprt_iter(fmd_adm_t *ap, fmd_adm_xprt_f *func, void *arg)
1009 {
1010         struct fmd_rpc_xprtlist rxl;
1011         uint_t i;
1012         enum clnt_stat cs;
1013         uint_t retries = 0;
1014 
1015         bzero(&rxl, sizeof (rxl)); /* tell xdr to allocate memory for us */
1016 
1017         do {
1018                 cs = fmd_adm_xprtlist_1(&rxl, ap->adm_clnt);
1019         } while (fmd_adm_retry(ap, cs, &retries));
1020 
1021         if (cs != RPC_SUCCESS)
1022                 return (fmd_adm_set_errno(ap, EPROTO));
1023 
1024         if (rxl.rxl_err != 0) {
1025                 xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl);
1026                 return (fmd_adm_set_svcerr(ap, rxl.rxl_err));
1027         }
1028 
1029         for (i = 0; i < rxl.rxl_len; i++)
1030                 func(rxl.rxl_buf.rxl_buf_val[i], arg);
1031 
1032         xdr_free(xdr_fmd_rpc_xprtlist, (char *)&rxl);
1033         return (0);
1034 }
1035 
1036 int
1037 fmd_adm_xprt_stats(fmd_adm_t *ap, id_t id, fmd_adm_stats_t *sp)
1038 {
1039         struct fmd_rpc_modstat rms;
1040         enum clnt_stat cs;
1041         uint_t retries = 0;
1042 
1043         if (sp == NULL)
1044                 return (fmd_adm_set_errno(ap, EINVAL));
1045 
1046         bzero(&rms, sizeof (rms)); /* tell xdr to allocate memory for us */
1047 
1048         do {
1049                 cs = fmd_adm_xprtstat_1(id, &rms, ap->adm_clnt);
1050         } while (fmd_adm_retry(ap, cs, &retries));
1051 
1052         if (cs != RPC_SUCCESS)
1053                 return (fmd_adm_set_errno(ap, EPROTO));
1054 
1055         if (rms.rms_err != 0) {
1056                 xdr_free(xdr_fmd_rpc_modstat, (char *)&rms);
1057                 return (fmd_adm_set_svcerr(ap, rms.rms_err));
1058         }
1059 
1060         sp->ams_buf = rms.rms_buf.rms_buf_val;
1061         sp->ams_len = rms.rms_buf.rms_buf_len;
1062 
1063         return (0);
1064 }
1065 
1066 int
1067 fmd_adm_log_rotate(fmd_adm_t *ap, const char *log)
1068 {
1069         int err;
1070         enum clnt_stat cs;
1071         uint_t retries = 0;
1072 
1073         if (log == NULL)
1074                 return (fmd_adm_set_errno(ap, EINVAL));
1075 
1076         do {
1077                 cs = fmd_adm_logrotate_1((char *)log, &err, ap->adm_clnt);
1078         } while (fmd_adm_retry(ap, cs, &retries));
1079 
1080         if (cs != RPC_SUCCESS)
1081                 return (fmd_adm_set_errno(ap, EPROTO));
1082 
1083         return (fmd_adm_set_svcerr(ap, err));
1084 }
1085 
1086 /*
1087  * Custom XDR routine for our API structure fmd_stat_t.  This function must
1088  * match the definition of fmd_stat_t in <fm/fmd_api.h> and must also match
1089  * the corresponding routine in usr/src/cmd/fm/fmd/common/fmd_rpc_adm.c.
1090  */
1091 bool_t
1092 xdr_fmd_stat(XDR *xp, fmd_stat_t *sp)
1093 {
1094         bool_t rv = TRUE;
1095 
1096         rv &= xdr_opaque(xp, sp->fmds_name, sizeof (sp->fmds_name));
1097         rv &= xdr_u_int(xp, &sp->fmds_type);
1098         rv &= xdr_opaque(xp, sp->fmds_desc, sizeof (sp->fmds_desc));
1099 
1100         switch (sp->fmds_type) {
1101         case FMD_TYPE_BOOL:
1102                 rv &= xdr_int(xp, &sp->fmds_value.bool);
1103                 break;
1104         case FMD_TYPE_INT32:
1105                 rv &= xdr_int32_t(xp, &sp->fmds_value.i32);
1106                 break;
1107         case FMD_TYPE_UINT32:
1108                 rv &= xdr_uint32_t(xp, &sp->fmds_value.ui32);
1109                 break;
1110         case FMD_TYPE_INT64:
1111                 rv &= xdr_int64_t(xp, &sp->fmds_value.i64);
1112                 break;
1113         case FMD_TYPE_UINT64:
1114         case FMD_TYPE_TIME:
1115         case FMD_TYPE_SIZE:
1116                 rv &= xdr_uint64_t(xp, &sp->fmds_value.ui64);
1117                 break;
1118         case FMD_TYPE_STRING:
1119                 rv &= xdr_string(xp, &sp->fmds_value.str, ~0);
1120                 break;
1121         }
1122 
1123         return (rv);
1124 }