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