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 *
fmd_adm_open(const char * host,uint32_t prog,int version)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
fmd_adm_close(fmd_adm_t * ap)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 *
fmd_adm_svc_errmsg(enum fmd_adm_error err)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 *
fmd_adm_errmsg(fmd_adm_t * ap)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
fmd_adm_set_svcerr(fmd_adm_t * ap,enum fmd_adm_error err)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
fmd_adm_set_errno(fmd_adm_t * ap,int err)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
fmd_adm_stats_cmp(const void * lp,const void * rp)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
fmd_adm_retry(fmd_adm_t * ap,enum clnt_stat cs,uint_t * retries)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
fmd_adm_stats_read(fmd_adm_t * ap,const char * name,fmd_adm_stats_t * sp)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
fmd_adm_stats_free(fmd_adm_t * ap,fmd_adm_stats_t * sp)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
fmd_adm_module_cmp(const void * lp,const void * rp)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
fmd_adm_module_iter(fmd_adm_t * ap,fmd_adm_module_f * func,void * arg)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
fmd_adm_module_load(fmd_adm_t * ap,const char * path)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
fmd_adm_module_unload(fmd_adm_t * ap,const char * name)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
fmd_adm_module_reset(fmd_adm_t * ap,const char * name)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
fmd_adm_module_gc(fmd_adm_t * ap,const char * name)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
fmd_adm_module_stats(fmd_adm_t * ap,const char * name,fmd_adm_stats_t * sp)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
fmd_adm_rsrc_count(fmd_adm_t * ap,int all,uint32_t * rcp)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
fmd_adm_rsrc_cmp(const void * lp,const void * rp)493 fmd_adm_rsrc_cmp(const void *lp, const void *rp)
494 {
495 return (strcmp(*(char **)lp, *(char **)rp));
496 }
497
498 int
fmd_adm_rsrc_iter(fmd_adm_t * ap,int all,fmd_adm_rsrc_f * func,void * arg)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
fmd_adm_rsrc_flush(fmd_adm_t * ap,const char * fmri)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
fmd_adm_rsrc_repaired(fmd_adm_t * ap,const char * fmri)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
fmd_adm_rsrc_replaced(fmd_adm_t * ap,const char * fmri)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
fmd_adm_rsrc_acquit(fmd_adm_t * ap,const char * fmri,const char * uuid)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
fmd_adm_case_repair(fmd_adm_t * ap,const char * uuid)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
fmd_adm_case_acquit(fmd_adm_t * ap,const char * uuid)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
fmd_adm_case_cmp(const void * lp,const void * rp)725 fmd_adm_case_cmp(const void *lp, const void *rp)
726 {
727 return (strcmp(*(char **)lp, *(char **)rp));
728 }
729
730 static int
fmd_adm_case_one(fmd_adm_caseinfo_t * acp,const char * url_token,fmd_adm_case_f * func,void * arg)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
fmd_adm_case_iter(fmd_adm_t * ap,const char * url_token,fmd_adm_case_f * func,void * arg)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
fmd_adm_serd_cmp(const void * lp,const void * rp)891 fmd_adm_serd_cmp(const void *lp, const void *rp)
892 {
893 return (strcmp(*(char **)lp, *(char **)rp));
894 }
895
896 int
fmd_adm_serd_iter(fmd_adm_t * ap,const char * name,fmd_adm_serd_f * func,void * arg)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
fmd_adm_serd_reset(fmd_adm_t * ap,const char * mod,const char * name)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
fmd_adm_xprt_iter(fmd_adm_t * ap,fmd_adm_xprt_f * func,void * arg)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
fmd_adm_xprt_stats(fmd_adm_t * ap,id_t id,fmd_adm_stats_t * sp)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
fmd_adm_log_rotate(fmd_adm_t * ap,const char * log)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
xdr_fmd_stat(XDR * xp,fmd_stat_t * sp)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 }
1125