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 }