Mercurial > illumos > illumos-gate
comparison usr/src/lib/libscf/common/notify_params.c @ 12979:ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
PSARC/2009/618 snmp-notify: SNMP Notification Daemon for Software Events
PSARC/2009/619 smtp-notify: Email Notification Daemon for Software Events
PSARC/2010/225 fmd for non-global Solaris zones
PSARC/2010/226 Solaris Instance UUID
PSARC/2010/227 nvlist_nvflag(3NVPAIR)
PSARC/2010/228 libfmevent additions
PSARC/2010/257 sysevent_evc_setpropnvl and sysevent_evc_getpropnvl
PSARC/2010/265 FMRI and FMA Event Stabilty, 'ireport' category 1 event class, and the 'sw' FMRI scheme
PSARC/2010/278 FMA/SMF integration: instance state transitions
PSARC/2010/279 Modelling panics within FMA
PSARC/2010/290 logadm.conf upgrade
6392476 fmdump needs to pretty-print
6393375 userland ereport/ireport event generation interfaces
6445732 Add email notification agent for FMA and software events
6804168 RFE: Allow an efficient means to monitor SMF services status changes
6866661 scf_values_destroy(3SCF) will segfault if is passed NULL
6884709 Add snmp notification agent for FMA and software events
6884712 Add private interface to tap into libfmd_msg macro expansion capabilities
6897919 fmd to run in a non-global zone
6897937 fmd use of non-private doors is not safe
6900081 add a UUID to Solaris kernel image for use in crashdump identification
6914884 model panic events as a defect diagnosis in FMA
6944862 fmd_case_open_uuid, fmd_case_uuisresolved, fmd_nvl_create_defect
6944866 log legacy sysevents in fmd
6944867 enumerate svc scheme in topo
6944868 software-diagnosis and software-response fmd modules
6944870 model SMF maintenance state as a defect diagnosis in FMA
6944876 savecore runs in foreground for systems with zfs root and dedicated dump
6965796 Implement notification parameters for SMF state transitions and FMA events
6968287 SUN-FM-MIB.mib needs to be updated to reflect Oracle information
6972331 logadm.conf upgrade PSARC/2010/290
author | Gavin Maltby <gavin.maltby@oracle.com> |
---|---|
date | Fri, 30 Jul 2010 17:04:17 +1000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
12978:19d842faf8e4 | 12979:ab9ae749152f |
---|---|
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 (c) 2010, Oracle and/or its affiliates. All rights reserved. | |
24 */ | |
25 | |
26 #include "libscf_impl.h" | |
27 | |
28 #include <assert.h> | |
29 #include <strings.h> | |
30 | |
31 /* | |
32 * Errors returned by smf_notify_{del|get|set}_params() | |
33 */ | |
34 static const scf_error_t errs_1[] = { | |
35 SCF_ERROR_BACKEND_ACCESS, | |
36 SCF_ERROR_BACKEND_READONLY, | |
37 SCF_ERROR_CONNECTION_BROKEN, | |
38 SCF_ERROR_DELETED, | |
39 SCF_ERROR_INTERNAL, | |
40 SCF_ERROR_INVALID_ARGUMENT, | |
41 SCF_ERROR_NO_MEMORY, | |
42 SCF_ERROR_NO_RESOURCES, | |
43 SCF_ERROR_NOT_FOUND, | |
44 SCF_ERROR_PERMISSION_DENIED, | |
45 0 | |
46 }; | |
47 | |
48 /* | |
49 * Errors returned by smf_notify_{del|get|set}_params() | |
50 * Except SCF_ERROR_INVALID_ARGUMENT | |
51 */ | |
52 static const scf_error_t errs_2[] = { | |
53 SCF_ERROR_BACKEND_ACCESS, | |
54 SCF_ERROR_BACKEND_READONLY, | |
55 SCF_ERROR_CONNECTION_BROKEN, | |
56 SCF_ERROR_DELETED, | |
57 SCF_ERROR_INTERNAL, | |
58 SCF_ERROR_NO_MEMORY, | |
59 SCF_ERROR_NO_RESOURCES, | |
60 SCF_ERROR_NOT_FOUND, | |
61 SCF_ERROR_PERMISSION_DENIED, | |
62 0 | |
63 }; | |
64 | |
65 /* | |
66 * Helper function that abort() on unexpected errors. | |
67 * The expected error set is a zero-terminated array of scf_error_t | |
68 */ | |
69 static int | |
70 check_scf_error(scf_error_t e, const scf_error_t *errs) | |
71 { | |
72 if (ismember(e, errs)) | |
73 return (1); | |
74 | |
75 assert(0); | |
76 abort(); | |
77 | |
78 /*NOTREACHED*/ | |
79 } | |
80 | |
81 /* | |
82 * Mapping of state transition to pgname. | |
83 */ | |
84 static struct st_pgname { | |
85 const char *st_pgname; | |
86 int32_t st_state; | |
87 } st_pgnames[] = { | |
88 { "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) }, | |
89 { "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) }, | |
90 { "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) }, | |
91 { "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) }, | |
92 { "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) }, | |
93 { "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) }, | |
94 { "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) }, | |
95 { "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) }, | |
96 { "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) }, | |
97 { "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) }, | |
98 { "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) }, | |
99 { "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) }, | |
100 { NULL, 0 } | |
101 }; | |
102 | |
103 /* | |
104 * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS | |
105 * | |
106 * returns 1, otherwise return 0 | |
107 */ | |
108 static boolean_t | |
109 is_svc_stn(const char *class) | |
110 { | |
111 int n = strlen(SCF_SVC_TRANSITION_CLASS); | |
112 | |
113 if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0) | |
114 if (class[n] == '\0' || class[n] == '.') | |
115 return (1); | |
116 return (0); | |
117 } | |
118 | |
119 /* | |
120 * Return the len of the base class. For instance, "class.class1.class2.*" | |
121 * will return the length of "class.class1.class2" | |
122 * This function does not check if the class or base class is valid. | |
123 * A class such as "class.class1....****" is not valid but will return the | |
124 * length of "class.class1....***" | |
125 */ | |
126 static size_t | |
127 base_class_len(const char *c) | |
128 { | |
129 const char *p; | |
130 size_t n; | |
131 | |
132 if ((n = strlen(c)) == 0) | |
133 return (0); | |
134 | |
135 p = c + n; | |
136 | |
137 /* get rid of any trailing asterisk */ | |
138 if (*--p == '*') | |
139 n--; | |
140 | |
141 /* make sure the class doesn't end in '.' */ | |
142 while (p >= c && *--p == '.') | |
143 n--; | |
144 | |
145 return (n); | |
146 } | |
147 | |
148 /* | |
149 * Allocates and builds the pgname for an FMA dotted class. | |
150 * The pgname will be of the form "class.class1.class2,SCF_NOTIFY_PG_POSTFIX" | |
151 * | |
152 * NULL on error | |
153 */ | |
154 static char * | |
155 class_to_pgname(const char *class) | |
156 { | |
157 size_t n; | |
158 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; | |
159 char *pgname = NULL; | |
160 | |
161 n = base_class_len(class); | |
162 | |
163 if (n == 0) { | |
164 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
165 return (NULL); | |
166 } | |
167 | |
168 if ((pgname = malloc(sz)) == NULL) { | |
169 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
170 goto error; | |
171 } | |
172 | |
173 if (snprintf(pgname, sz, "%.*s,%s", (int)n, class, | |
174 SCF_NOTIFY_PG_POSTFIX) >= sz) { | |
175 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
176 goto error; | |
177 } | |
178 return (pgname); | |
179 | |
180 error: | |
181 free(pgname); | |
182 pgname = NULL; | |
183 | |
184 return (pgname); | |
185 } | |
186 | |
187 /* | |
188 * Get the pg from the running snapshot of the instance (composed or not) | |
189 */ | |
190 static int | |
191 get_pg(scf_service_t *s, scf_instance_t *i, const char *n, | |
192 scf_propertygroup_t *pg, int composed) | |
193 { | |
194 scf_handle_t *h = scf_instance_handle(i); | |
195 scf_error_t scf_e = scf_error(); | |
196 scf_snapshot_t *snap = scf_snapshot_create(h); | |
197 scf_snaplevel_t *slvl = scf_snaplevel_create(h); | |
198 int r = -1; | |
199 | |
200 if (h == NULL) { | |
201 /* | |
202 * Use the error stored in scf_e | |
203 */ | |
204 (void) scf_set_error(scf_e); | |
205 goto out; | |
206 } | |
207 if (s == NULL) { | |
208 if (snap == NULL || slvl == NULL) | |
209 goto out; | |
210 if (scf_instance_get_snapshot(i, "running", snap) != 0) | |
211 goto out; | |
212 | |
213 if (composed) { | |
214 if (scf_instance_get_pg_composed(i, snap, n, pg) != 0) | |
215 goto out; | |
216 } else { | |
217 if (scf_snapshot_get_base_snaplevel(snap, slvl) != 0 || | |
218 scf_snaplevel_get_pg(slvl, n, pg) != 0) | |
219 goto out; | |
220 } | |
221 } else { | |
222 if (scf_service_get_pg(s, n, pg) != 0) | |
223 goto out; | |
224 } | |
225 | |
226 r = 0; | |
227 out: | |
228 scf_snaplevel_destroy(slvl); | |
229 scf_snapshot_destroy(snap); | |
230 | |
231 return (r); | |
232 } | |
233 | |
234 /* | |
235 * Add a pg if it does not exist, or get it if it exists. | |
236 * It operates on the instance if the service parameter is NULL. | |
237 * | |
238 * returns 0 on success or -1 on failure | |
239 */ | |
240 static int | |
241 get_or_add_pg(scf_service_t *s, scf_instance_t *i, const char *n, const char *t, | |
242 uint32_t flags, scf_propertygroup_t *pg) | |
243 { | |
244 int r; | |
245 | |
246 if (s == NULL) | |
247 r = scf_instance_add_pg(i, n, t, flags, pg); | |
248 else | |
249 r = scf_service_add_pg(s, n, t, flags, pg); | |
250 | |
251 if (r == 0) | |
252 return (0); | |
253 else if (scf_error() != SCF_ERROR_EXISTS) | |
254 return (-1); | |
255 | |
256 if (s == NULL) | |
257 r = scf_instance_get_pg(i, n, pg); | |
258 else | |
259 r = scf_service_get_pg(s, n, pg); | |
260 | |
261 return (r); | |
262 } | |
263 | |
264 /* | |
265 * Delete the property group form the instance or service. | |
266 * If service is NULL, use instance, otherwise use only the service. | |
267 * | |
268 * Return SCF_SUCCESS or SCF_FAILED on | |
269 * SCF_ERROR_BACKEND_ACCESS | |
270 * SCF_ERROR_BACKEND_READONLY | |
271 * SCF_ERROR_CONNECTION_BROKEN | |
272 * SCF_ERROR_DELETED | |
273 * SCF_ERROR_HANDLE_MISMATCH | |
274 * SCF_ERROR_INTERNAL | |
275 * SCF_ERROR_INVALID_ARGUMENT | |
276 * SCF_ERROR_NO_RESOURCES | |
277 * SCF_ERROR_NOT_BOUND | |
278 * SCF_ERROR_NOT_FOUND | |
279 * SCF_ERROR_NOT_SET | |
280 * SCF_ERROR_PERMISSION_DENIED | |
281 */ | |
282 static int | |
283 del_pg(scf_service_t *s, scf_instance_t *i, const char *n, | |
284 scf_propertygroup_t *pg) | |
285 { | |
286 if ((s == NULL ? scf_instance_get_pg(i, n, pg) : | |
287 scf_service_get_pg(s, n, pg)) != SCF_SUCCESS) | |
288 if (scf_error() == SCF_ERROR_NOT_FOUND) | |
289 return (SCF_SUCCESS); | |
290 else | |
291 return (SCF_FAILED); | |
292 | |
293 if (scf_pg_delete(pg) != SCF_SUCCESS) | |
294 if (scf_error() == SCF_ERROR_DELETED) | |
295 return (SCF_SUCCESS); | |
296 else | |
297 return (SCF_FAILED); | |
298 | |
299 return (SCF_SUCCESS); | |
300 } | |
301 | |
302 static scf_type_t | |
303 get_scf_type(nvpair_t *p) | |
304 { | |
305 switch (nvpair_type(p)) { | |
306 case DATA_TYPE_BOOLEAN: | |
307 case DATA_TYPE_BOOLEAN_VALUE: | |
308 case DATA_TYPE_BOOLEAN_ARRAY: | |
309 return (SCF_TYPE_BOOLEAN); | |
310 | |
311 case DATA_TYPE_BYTE: | |
312 case DATA_TYPE_UINT8: | |
313 case DATA_TYPE_UINT16: | |
314 case DATA_TYPE_UINT32: | |
315 case DATA_TYPE_UINT64: | |
316 case DATA_TYPE_BYTE_ARRAY: | |
317 case DATA_TYPE_UINT8_ARRAY: | |
318 case DATA_TYPE_UINT16_ARRAY: | |
319 case DATA_TYPE_UINT32_ARRAY: | |
320 case DATA_TYPE_UINT64_ARRAY: | |
321 return (SCF_TYPE_COUNT); | |
322 | |
323 case DATA_TYPE_INT8: | |
324 case DATA_TYPE_INT16: | |
325 case DATA_TYPE_INT32: | |
326 case DATA_TYPE_INT64: | |
327 case DATA_TYPE_INT8_ARRAY: | |
328 case DATA_TYPE_INT16_ARRAY: | |
329 case DATA_TYPE_INT32_ARRAY: | |
330 case DATA_TYPE_INT64_ARRAY: | |
331 return (SCF_TYPE_INTEGER); | |
332 | |
333 case DATA_TYPE_STRING: | |
334 case DATA_TYPE_STRING_ARRAY: | |
335 return (SCF_TYPE_ASTRING); | |
336 | |
337 default: | |
338 return (SCF_TYPE_INVALID); | |
339 } | |
340 } | |
341 | |
342 static int | |
343 add_entry(scf_transaction_entry_t *te, scf_value_t *val) | |
344 { | |
345 if (scf_entry_add_value(te, val) != 0) { | |
346 scf_value_destroy(val); | |
347 return (SCF_FAILED); | |
348 } | |
349 | |
350 return (SCF_SUCCESS); | |
351 } | |
352 | |
353 static int | |
354 add_boolean_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint8_t v) | |
355 { | |
356 scf_value_t *val = scf_value_create(h); | |
357 | |
358 if (val == NULL) | |
359 return (SCF_FAILED); | |
360 | |
361 scf_value_set_boolean(val, v); | |
362 | |
363 return (add_entry(te, val)); | |
364 } | |
365 | |
366 static int | |
367 add_count_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint64_t v) | |
368 { | |
369 scf_value_t *val = scf_value_create(h); | |
370 | |
371 if (val == NULL) | |
372 return (SCF_FAILED); | |
373 | |
374 scf_value_set_count(val, v); | |
375 | |
376 return (add_entry(te, val)); | |
377 } | |
378 | |
379 static int | |
380 add_integer_entry(scf_handle_t *h, scf_transaction_entry_t *te, int64_t v) | |
381 { | |
382 scf_value_t *val = scf_value_create(h); | |
383 | |
384 if (val == NULL) | |
385 return (SCF_FAILED); | |
386 | |
387 scf_value_set_integer(val, v); | |
388 | |
389 return (add_entry(te, val)); | |
390 } | |
391 | |
392 static int | |
393 add_astring_entry(scf_handle_t *h, scf_transaction_entry_t *te, char *s) | |
394 { | |
395 scf_value_t *val = scf_value_create(h); | |
396 | |
397 if (val == NULL) | |
398 return (SCF_FAILED); | |
399 | |
400 if (scf_value_set_astring(val, s) != 0) { | |
401 scf_value_destroy(val); | |
402 return (SCF_FAILED); | |
403 } | |
404 | |
405 return (add_entry(te, val)); | |
406 } | |
407 | |
408 static int | |
409 get_nvpair_vals(scf_handle_t *h, scf_transaction_entry_t *te, nvpair_t *p) | |
410 { | |
411 scf_value_t *val = scf_value_create(h); | |
412 uint_t n = 1; | |
413 int i; | |
414 | |
415 if (val == NULL) | |
416 return (SCF_FAILED); | |
417 | |
418 switch (nvpair_type(p)) { | |
419 case DATA_TYPE_BOOLEAN: | |
420 return (add_boolean_entry(h, te, 1)); | |
421 case DATA_TYPE_BOOLEAN_VALUE: | |
422 { | |
423 boolean_t v; | |
424 | |
425 (void) nvpair_value_boolean_value(p, &v); | |
426 return (add_boolean_entry(h, te, (uint8_t)v)); | |
427 } | |
428 case DATA_TYPE_BOOLEAN_ARRAY: | |
429 { | |
430 boolean_t *v; | |
431 | |
432 (void) nvpair_value_boolean_array(p, &v, &n); | |
433 for (i = 0; i < n; ++i) { | |
434 if (add_boolean_entry(h, te, (uint8_t)v[i]) != | |
435 SCF_SUCCESS) | |
436 return (SCF_FAILED); | |
437 } | |
438 return (SCF_SUCCESS); | |
439 } | |
440 case DATA_TYPE_BYTE: | |
441 { | |
442 uchar_t v; | |
443 | |
444 (void) nvpair_value_byte(p, &v); | |
445 return (add_count_entry(h, te, v)); | |
446 } | |
447 case DATA_TYPE_UINT8: | |
448 { | |
449 uint8_t v; | |
450 | |
451 (void) nvpair_value_uint8(p, &v); | |
452 return (add_count_entry(h, te, v)); | |
453 } | |
454 case DATA_TYPE_UINT16: | |
455 { | |
456 uint16_t v; | |
457 | |
458 (void) nvpair_value_uint16(p, &v); | |
459 return (add_count_entry(h, te, v)); | |
460 } | |
461 case DATA_TYPE_UINT32: | |
462 { | |
463 uint32_t v; | |
464 | |
465 (void) nvpair_value_uint32(p, &v); | |
466 return (add_count_entry(h, te, v)); | |
467 } | |
468 case DATA_TYPE_UINT64: | |
469 { | |
470 uint64_t v; | |
471 | |
472 (void) nvpair_value_uint64(p, &v); | |
473 return (add_count_entry(h, te, v)); | |
474 } | |
475 case DATA_TYPE_BYTE_ARRAY: | |
476 { | |
477 uchar_t *v; | |
478 | |
479 (void) nvpair_value_byte_array(p, &v, &n); | |
480 for (i = 0; i < n; ++i) { | |
481 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) | |
482 return (SCF_FAILED); | |
483 } | |
484 return (SCF_SUCCESS); | |
485 } | |
486 case DATA_TYPE_UINT8_ARRAY: | |
487 { | |
488 uint8_t *v; | |
489 | |
490 (void) nvpair_value_uint8_array(p, &v, &n); | |
491 for (i = 0; i < n; ++i) { | |
492 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) | |
493 return (SCF_FAILED); | |
494 } | |
495 return (SCF_SUCCESS); | |
496 } | |
497 case DATA_TYPE_UINT16_ARRAY: | |
498 { | |
499 uint16_t *v; | |
500 | |
501 (void) nvpair_value_uint16_array(p, &v, &n); | |
502 for (i = 0; i < n; ++i) { | |
503 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) | |
504 return (SCF_FAILED); | |
505 } | |
506 return (SCF_SUCCESS); | |
507 } | |
508 case DATA_TYPE_UINT32_ARRAY: | |
509 { | |
510 uint32_t *v; | |
511 | |
512 (void) nvpair_value_uint32_array(p, &v, &n); | |
513 for (i = 0; i < n; ++i) { | |
514 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) | |
515 return (SCF_FAILED); | |
516 } | |
517 return (SCF_SUCCESS); | |
518 } | |
519 case DATA_TYPE_UINT64_ARRAY: | |
520 { | |
521 uint64_t *v; | |
522 | |
523 (void) nvpair_value_uint64_array(p, &v, &n); | |
524 for (i = 0; i < n; ++i) { | |
525 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS) | |
526 return (SCF_FAILED); | |
527 } | |
528 return (SCF_SUCCESS); | |
529 } | |
530 case DATA_TYPE_INT8: | |
531 { | |
532 int8_t v; | |
533 | |
534 (void) nvpair_value_int8(p, &v); | |
535 return (add_integer_entry(h, te, v)); | |
536 } | |
537 case DATA_TYPE_INT16: | |
538 { | |
539 int16_t v; | |
540 | |
541 (void) nvpair_value_int16(p, &v); | |
542 return (add_integer_entry(h, te, v)); | |
543 } | |
544 case DATA_TYPE_INT32: | |
545 { | |
546 int32_t v; | |
547 | |
548 (void) nvpair_value_int32(p, &v); | |
549 return (add_integer_entry(h, te, v)); | |
550 } | |
551 case DATA_TYPE_INT64: | |
552 { | |
553 int64_t v; | |
554 | |
555 (void) nvpair_value_int64(p, &v); | |
556 return (add_integer_entry(h, te, v)); | |
557 } | |
558 case DATA_TYPE_INT8_ARRAY: | |
559 { | |
560 int8_t *v; | |
561 | |
562 (void) nvpair_value_int8_array(p, &v, &n); | |
563 for (i = 0; i < n; ++i) { | |
564 if (add_integer_entry(h, te, v[i]) != | |
565 SCF_SUCCESS) | |
566 return (SCF_FAILED); | |
567 } | |
568 return (SCF_SUCCESS); | |
569 } | |
570 case DATA_TYPE_INT16_ARRAY: | |
571 { | |
572 int16_t *v; | |
573 | |
574 (void) nvpair_value_int16_array(p, &v, &n); | |
575 for (i = 0; i < n; ++i) { | |
576 if (add_integer_entry(h, te, v[i]) != | |
577 SCF_SUCCESS) | |
578 return (SCF_FAILED); | |
579 } | |
580 return (SCF_SUCCESS); | |
581 } | |
582 case DATA_TYPE_INT32_ARRAY: | |
583 { | |
584 int32_t *v; | |
585 | |
586 (void) nvpair_value_int32_array(p, &v, &n); | |
587 for (i = 0; i < n; ++i) { | |
588 if (add_integer_entry(h, te, v[i]) != | |
589 SCF_SUCCESS) | |
590 return (SCF_FAILED); | |
591 } | |
592 return (SCF_SUCCESS); | |
593 } | |
594 case DATA_TYPE_INT64_ARRAY: | |
595 { | |
596 int64_t *v; | |
597 | |
598 (void) nvpair_value_int64_array(p, &v, &n); | |
599 for (i = 0; i < n; ++i) { | |
600 if (add_integer_entry(h, te, v[i]) != | |
601 SCF_SUCCESS) | |
602 return (SCF_FAILED); | |
603 } | |
604 return (SCF_SUCCESS); | |
605 } | |
606 case DATA_TYPE_STRING: | |
607 { | |
608 char *str; | |
609 | |
610 (void) nvpair_value_string(p, &str); | |
611 return (add_astring_entry(h, te, str)); | |
612 } | |
613 case DATA_TYPE_STRING_ARRAY: | |
614 { | |
615 char **v; | |
616 | |
617 (void) nvpair_value_string_array(p, &v, &n); | |
618 for (i = 0; i < n; ++i) { | |
619 if (add_astring_entry(h, te, v[i]) != | |
620 SCF_SUCCESS) | |
621 return (SCF_FAILED); | |
622 } | |
623 return (SCF_SUCCESS); | |
624 } | |
625 default: | |
626 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
627 return (SCF_FAILED); | |
628 } | |
629 | |
630 /*NOTREACHED*/ | |
631 } | |
632 | |
633 /* | |
634 * Add new transaction entry to scf_transaction_t | |
635 * | |
636 * Can fail with | |
637 * SCF_ERROR_BACKEND_ACCESS | |
638 * SCF_ERROR_CONNECTION_BROKEN | |
639 * SCF_ERROR_DELETED | |
640 * SCF_ERROR_INTERNAL | |
641 * SCF_ERROR_NO_RESOURCES | |
642 * SCF_ERROR_NOT_FOUND | |
643 */ | |
644 static int | |
645 prep_transaction(scf_transaction_t *tx, scf_transaction_entry_t *te, | |
646 const char *prop, scf_type_t type) | |
647 { | |
648 if (scf_transaction_property_new(tx, te, prop, type) != SCF_SUCCESS && | |
649 (scf_error() != SCF_ERROR_EXISTS || | |
650 scf_transaction_property_change(tx, te, prop, type) != | |
651 SCF_SUCCESS)) { | |
652 if (check_scf_error(scf_error(), errs_2)) { | |
653 return (SCF_FAILED); | |
654 } | |
655 } | |
656 | |
657 return (SCF_SUCCESS); | |
658 } | |
659 | |
660 /* | |
661 * notify_set_params() | |
662 * returns 0 on success or -1 on failure | |
663 * SCF_ERROR_BACKEND_ACCESS | |
664 * SCF_ERROR_BACKEND_READONLY | |
665 * SCF_ERROR_CONNECTION_BROKEN | |
666 * SCF_ERROR_DELETED | |
667 * SCF_ERROR_INTERNAL | |
668 * SCF_ERROR_INVALID_ARGUMENT | |
669 * SCF_ERROR_NO_MEMORY | |
670 * SCF_ERROR_NO_RESOURCES | |
671 * SCF_ERROR_NOT_FOUND | |
672 * SCF_ERROR_PERMISSION_DENIED | |
673 */ | |
674 static int | |
675 notify_set_params(scf_propertygroup_t *pg, nvlist_t *params) | |
676 { | |
677 scf_handle_t *h = scf_pg_handle(pg); | |
678 scf_error_t scf_e = scf_error(); | |
679 scf_transaction_t *tx = scf_transaction_create(h); | |
680 int bufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; | |
681 char *propname = malloc(bufsz); | |
682 int r = -1; | |
683 int err; | |
684 | |
685 if (h == NULL) { | |
686 /* | |
687 * Use the error stored in scf_e | |
688 */ | |
689 (void) scf_set_error(scf_e); | |
690 goto cleanup; | |
691 } | |
692 if (tx == NULL) | |
693 goto cleanup; | |
694 | |
695 if (propname == NULL) { | |
696 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
697 goto cleanup; | |
698 } | |
699 | |
700 do { | |
701 nvpair_t *nvp; | |
702 | |
703 /* | |
704 * make sure we have the most recent version of the pg | |
705 * start the transaction | |
706 */ | |
707 if (scf_pg_update(pg) == SCF_FAILED || | |
708 scf_transaction_start(tx, pg) != SCF_SUCCESS) { | |
709 if (check_scf_error(scf_error(), errs_2)) { | |
710 goto cleanup; | |
711 } | |
712 } | |
713 | |
714 for (nvp = nvlist_next_nvpair(params, NULL); nvp != NULL; | |
715 nvp = nvlist_next_nvpair(params, nvp)) { | |
716 nvlist_t *m; | |
717 nvpair_t *p; | |
718 | |
719 /* we ONLY take nvlists here */ | |
720 if (nvpair_type(nvp) != DATA_TYPE_NVLIST) { | |
721 char *name = nvpair_name(nvp); | |
722 | |
723 /* | |
724 * if this is output from | |
725 * smf_notify_get_params() we want to skip | |
726 * the tset value of the nvlist | |
727 */ | |
728 if (strcmp(name, SCF_NOTIFY_NAME_TSET) == 0) | |
729 continue; | |
730 | |
731 (void) scf_set_error( | |
732 SCF_ERROR_INVALID_ARGUMENT); | |
733 goto cleanup; | |
734 } | |
735 | |
736 if (nvpair_value_nvlist(nvp, &m) != 0) { | |
737 (void) scf_set_error( | |
738 SCF_ERROR_INVALID_ARGUMENT); | |
739 goto cleanup; | |
740 } | |
741 | |
742 /* | |
743 * Traverse each mechanism list | |
744 */ | |
745 for (p = nvlist_next_nvpair(m, NULL); p != NULL; | |
746 p = nvlist_next_nvpair(m, p)) { | |
747 scf_transaction_entry_t *te = | |
748 scf_entry_create(h); | |
749 /* map the nvpair type to scf type */ | |
750 scf_type_t type = get_scf_type(p); | |
751 | |
752 if (te == NULL) { | |
753 if (scf_error() != | |
754 SCF_ERROR_INVALID_ARGUMENT) { | |
755 scf_entry_destroy(te); | |
756 goto cleanup; | |
757 } else { | |
758 assert(0); | |
759 abort(); | |
760 } | |
761 } | |
762 | |
763 if (type == SCF_TYPE_INVALID) { | |
764 (void) scf_set_error( | |
765 SCF_ERROR_INVALID_ARGUMENT); | |
766 scf_entry_destroy(te); | |
767 goto cleanup; | |
768 } | |
769 | |
770 if (snprintf(propname, bufsz, "%s,%s", | |
771 nvpair_name(nvp), nvpair_name(p)) >= | |
772 bufsz) { | |
773 (void) scf_set_error( | |
774 SCF_ERROR_INVALID_ARGUMENT); | |
775 scf_entry_destroy(te); | |
776 goto cleanup; | |
777 } | |
778 | |
779 if (prep_transaction(tx, te, propname, type) != | |
780 SCF_SUCCESS) { | |
781 scf_entry_destroy(te); | |
782 goto cleanup; | |
783 } | |
784 | |
785 if (get_nvpair_vals(h, te, p) != SCF_SUCCESS) { | |
786 if (check_scf_error(scf_error(), | |
787 errs_2)) { | |
788 goto cleanup; | |
789 } | |
790 } | |
791 } | |
792 } | |
793 err = scf_transaction_commit(tx); | |
794 scf_transaction_destroy_children(tx); | |
795 } while (err == 0); | |
796 | |
797 if (err == -1) { | |
798 if (check_scf_error(scf_error(), errs_2)) { | |
799 goto cleanup; | |
800 } | |
801 } | |
802 | |
803 r = 0; | |
804 | |
805 cleanup: | |
806 scf_transaction_destroy_children(tx); | |
807 scf_transaction_destroy(tx); | |
808 free(propname); | |
809 | |
810 return (r); | |
811 } | |
812 | |
813 /* | |
814 * Decode fmri. Populates service OR instance depending on which one is an | |
815 * exact match to the fmri parameter. | |
816 * | |
817 * The function destroys and sets the unused entity (service or instance) to | |
818 * NULL. | |
819 * | |
820 * return SCF_SUCCESS or SCF_FAILED on | |
821 * SCF_ERROR_BACKEND_ACCESS | |
822 * SCF_ERROR_CONNECTION_BROKEN | |
823 * SCF_ERROR_CONSTRAINT_VIOLATED | |
824 * SCF_ERROR_DELETED | |
825 * SCF_ERROR_HANDLE_MISMATCH | |
826 * SCF_ERROR_INTERNAL | |
827 * SCF_ERROR_INVALID_ARGUMENT | |
828 * SCF_ERROR_NO_RESOURCES | |
829 * SCF_ERROR_NOT_BOUND | |
830 * SCF_ERROR_NOT_FOUND | |
831 * SCF_ERROR_NOT_SET | |
832 */ | |
833 static int | |
834 decode_fmri(const char *fmri, scf_handle_t *h, scf_service_t **s, | |
835 scf_instance_t **i) | |
836 { | |
837 if (scf_handle_decode_fmri(h, fmri, NULL, *s, NULL, NULL, NULL, | |
838 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { | |
839 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { | |
840 scf_service_destroy(*s); | |
841 *s = NULL; | |
842 } else { | |
843 return (SCF_FAILED); | |
844 } | |
845 } | |
846 if (*s == NULL) | |
847 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, *i, | |
848 NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { | |
849 return (SCF_FAILED); | |
850 } | |
851 | |
852 return (SCF_SUCCESS); | |
853 } | |
854 | |
855 /* | |
856 * Return size in bytes for an SCF_TYPE_*. Not all libscf types are supported | |
857 */ | |
858 static int | |
859 get_type_size(scf_type_t t) | |
860 { | |
861 switch (t) { | |
862 case SCF_TYPE_BOOLEAN: | |
863 return (sizeof (uint8_t)); | |
864 case SCF_TYPE_COUNT: | |
865 return (sizeof (uint64_t)); | |
866 case SCF_TYPE_INTEGER: | |
867 return (sizeof (int64_t)); | |
868 case SCF_TYPE_ASTRING: | |
869 case SCF_TYPE_USTRING: | |
870 return (sizeof (void *)); | |
871 default: | |
872 return (-1); | |
873 } | |
874 | |
875 /*NOTREACHED*/ | |
876 } | |
877 | |
878 /* | |
879 * Return a pointer to the array of values according to its type | |
880 */ | |
881 static void ** | |
882 get_v_pointer(scf_values_t *v) | |
883 { | |
884 switch (v->value_type) { | |
885 case SCF_TYPE_BOOLEAN: | |
886 return ((void **)&v->values.v_boolean); | |
887 case SCF_TYPE_COUNT: | |
888 return ((void **)&v->values.v_count); | |
889 case SCF_TYPE_INTEGER: | |
890 return ((void **)&v->values.v_integer); | |
891 case SCF_TYPE_ASTRING: | |
892 return ((void **)&v->values.v_astring); | |
893 case SCF_TYPE_USTRING: | |
894 return ((void **)&v->values.v_ustring); | |
895 default: | |
896 return (NULL); | |
897 } | |
898 | |
899 /*NOTREACHED*/ | |
900 } | |
901 | |
902 /* | |
903 * Populate scf_values_t value array at position c. | |
904 */ | |
905 static int | |
906 get_value(scf_value_t *val, scf_values_t *v, int c, char *buf, int sz) | |
907 { | |
908 switch (v->value_type) { | |
909 case SCF_TYPE_BOOLEAN: | |
910 return (scf_value_get_boolean(val, v->values.v_boolean + c)); | |
911 case SCF_TYPE_COUNT: | |
912 return (scf_value_get_count(val, v->values.v_count + c)); | |
913 case SCF_TYPE_INTEGER: | |
914 return (scf_value_get_integer(val, v->values.v_integer + c)); | |
915 case SCF_TYPE_ASTRING: | |
916 if (scf_value_get_astring(val, buf, sz) < 0 || | |
917 (v->values.v_astring[c] = strdup(buf)) == NULL) { | |
918 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
919 return (-1); | |
920 } | |
921 return (0); | |
922 case SCF_TYPE_USTRING: | |
923 if (scf_value_get_ustring(val, buf, sz) < 0 || | |
924 (v->values.v_ustring[c] = strdup(buf)) == NULL) { | |
925 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
926 return (-1); | |
927 } | |
928 return (0); | |
929 default: | |
930 return (-1); | |
931 } | |
932 | |
933 /*NOTREACHED*/ | |
934 } | |
935 | |
936 /* | |
937 * Populate scf_values_t structure with values from prop | |
938 */ | |
939 static int | |
940 values_get(scf_property_t *prop, scf_values_t *v) | |
941 { | |
942 scf_handle_t *h = scf_property_handle(prop); | |
943 scf_error_t scf_e = scf_error(); | |
944 scf_value_t *val = scf_value_create(h); | |
945 scf_iter_t *it = scf_iter_create(h); | |
946 scf_type_t type = SCF_TYPE_INVALID; | |
947 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; | |
948 char *buf = malloc(sz); | |
949 void **p; | |
950 int err, elem_sz, count, cursz; | |
951 int r = SCF_FAILED; | |
952 | |
953 assert(v != NULL); | |
954 assert(v->reserved == NULL); | |
955 if (buf == NULL) { | |
956 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
957 goto cleanup; | |
958 } | |
959 if (h == NULL) { | |
960 /* | |
961 * Use the error stored in scf_e | |
962 */ | |
963 (void) scf_set_error(scf_e); | |
964 goto cleanup; | |
965 } | |
966 if (val == NULL || it == NULL) | |
967 goto cleanup; | |
968 | |
969 if (scf_property_type(prop, &type) != SCF_SUCCESS) | |
970 goto cleanup; | |
971 if (scf_property_is_type(prop, v->value_type) != SCF_SUCCESS) | |
972 goto error; | |
973 | |
974 elem_sz = get_type_size(type); | |
975 assert(elem_sz > 0); | |
976 | |
977 p = get_v_pointer(v); | |
978 assert(p != NULL); | |
979 | |
980 cursz = count = v->value_count; | |
981 if (scf_iter_property_values(it, prop) != 0) { | |
982 goto error; | |
983 } | |
984 | |
985 while ((err = scf_iter_next_value(it, val)) == 1) { | |
986 if (count + 1 >= cursz) { | |
987 void *tmp; | |
988 | |
989 /* set initial size or double it */ | |
990 cursz = cursz ? 2 * cursz : 8; | |
991 if ((tmp = realloc(*p, cursz * elem_sz)) == NULL) { | |
992 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
993 goto error; | |
994 } | |
995 *p = tmp; | |
996 } | |
997 | |
998 if (get_value(val, v, count, buf, sz) != 0) | |
999 goto error; | |
1000 | |
1001 count++; | |
1002 } | |
1003 | |
1004 v->value_count = count; | |
1005 | |
1006 if (err != 0) | |
1007 goto error; | |
1008 | |
1009 r = SCF_SUCCESS; | |
1010 goto cleanup; | |
1011 | |
1012 error: | |
1013 v->value_count = count; | |
1014 scf_values_destroy(v); | |
1015 | |
1016 cleanup: | |
1017 free(buf); | |
1018 scf_iter_destroy(it); | |
1019 scf_value_destroy(val); | |
1020 return (r); | |
1021 } | |
1022 | |
1023 /* | |
1024 * Add values from property p to existing nvlist_t nvl. The data type in the | |
1025 * nvlist is inferred from the scf_type_t of the property. | |
1026 * | |
1027 * Returns SCF_SUCCESS or SCF_FAILED on | |
1028 * SCF_ERROR_CONNECTION_BROKEN | |
1029 * SCF_ERROR_DELETED | |
1030 * SCF_ERROR_HANDLE_DESTROYED | |
1031 * SCF_ERROR_HANDLE_MISMATCH | |
1032 * SCF_ERROR_INVALID_ARGUMENT | |
1033 * SCF_ERROR_NO_MEMORY | |
1034 * SCF_ERROR_NO_RESOURCES | |
1035 * SCF_ERROR_NOT_BOUND | |
1036 * SCF_ERROR_NOT_SET | |
1037 * SCF_ERROR_PERMISSION_DENIED | |
1038 * SCF_ERROR_TYPE_MISMATCH | |
1039 */ | |
1040 static int | |
1041 add_prop_to_nvlist(scf_property_t *p, const char *pname, nvlist_t *nvl, | |
1042 int array) | |
1043 { | |
1044 scf_values_t vals = { 0 }; | |
1045 scf_type_t type, base_type; | |
1046 int r = SCF_FAILED; | |
1047 int err = 0; | |
1048 | |
1049 if (p == NULL || pname == NULL || *pname == '\0' || nvl == NULL) { | |
1050 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1051 return (r); | |
1052 } | |
1053 | |
1054 if (scf_property_type(p, &type) != 0) | |
1055 goto cleanup; | |
1056 | |
1057 /* | |
1058 * scf_values_t does not support subtypes of SCF_TYPE_USTRING, | |
1059 * mapping them all to SCF_TYPE_USTRING | |
1060 */ | |
1061 base_type = scf_true_base_type(type); | |
1062 if (base_type == SCF_TYPE_ASTRING && type != SCF_TYPE_ASTRING) | |
1063 type = SCF_TYPE_USTRING; | |
1064 | |
1065 vals.value_type = type; | |
1066 if (values_get(p, &vals) != SCF_SUCCESS) { | |
1067 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { | |
1068 assert(0); | |
1069 abort(); | |
1070 } | |
1071 goto cleanup; | |
1072 } | |
1073 | |
1074 switch (vals.value_type) { | |
1075 case SCF_TYPE_BOOLEAN: | |
1076 { | |
1077 boolean_t *v; | |
1078 int i; | |
1079 int n = vals.value_count; | |
1080 | |
1081 v = calloc(n, sizeof (boolean_t)); | |
1082 if (v == NULL) { | |
1083 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1084 goto cleanup; | |
1085 } | |
1086 for (i = 0; i < n; ++i) | |
1087 v[i] = (boolean_t)vals.values.v_boolean[i]; | |
1088 | |
1089 if (n == 1 && !array) | |
1090 err = nvlist_add_boolean_value(nvl, pname, *v); | |
1091 else | |
1092 err = nvlist_add_boolean_array(nvl, pname, | |
1093 v, n); | |
1094 if (err != 0) { | |
1095 free(v); | |
1096 goto cleanup; | |
1097 } | |
1098 free(v); | |
1099 } | |
1100 break; | |
1101 | |
1102 case SCF_TYPE_COUNT: | |
1103 if (vals.value_count == 1 && !array) | |
1104 err = nvlist_add_uint64(nvl, pname, | |
1105 *vals.values.v_count); | |
1106 else | |
1107 err = nvlist_add_uint64_array(nvl, pname, | |
1108 vals.values.v_count, vals.value_count); | |
1109 if (err != 0) | |
1110 goto cleanup; | |
1111 | |
1112 break; | |
1113 | |
1114 case SCF_TYPE_INTEGER: | |
1115 if (vals.value_count == 1 && !array) | |
1116 err = nvlist_add_int64(nvl, pname, | |
1117 *vals.values.v_integer); | |
1118 else | |
1119 err = nvlist_add_int64_array(nvl, pname, | |
1120 vals.values.v_integer, vals.value_count); | |
1121 if (err != 0) | |
1122 goto cleanup; | |
1123 | |
1124 break; | |
1125 | |
1126 case SCF_TYPE_ASTRING: | |
1127 if (vals.value_count == 1 && !array) | |
1128 err = nvlist_add_string(nvl, pname, | |
1129 *vals.values.v_astring); | |
1130 else | |
1131 err = nvlist_add_string_array(nvl, pname, | |
1132 vals.values.v_astring, vals.value_count); | |
1133 if (err != 0) | |
1134 goto cleanup; | |
1135 break; | |
1136 | |
1137 default: | |
1138 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1139 goto cleanup; | |
1140 } | |
1141 | |
1142 r = SCF_SUCCESS; | |
1143 cleanup: | |
1144 scf_values_destroy(&vals); | |
1145 switch (err) { | |
1146 case 0: | |
1147 break; | |
1148 case EINVAL: | |
1149 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1150 break; | |
1151 case ENOMEM: | |
1152 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1153 break; | |
1154 default: | |
1155 /* we should *never* get here */ | |
1156 abort(); | |
1157 } | |
1158 | |
1159 return (r); | |
1160 } | |
1161 | |
1162 /* | |
1163 * Parse property name "mechanism,parameter" into separate mechanism | |
1164 * and parameter. *mech must be freed by caller. *val points into | |
1165 * *mech and must not be freed. | |
1166 * | |
1167 * Returns SCF_SUCCESS or SCF_FAILED on | |
1168 * SCF_ERROR_NO_MEMORY | |
1169 * SCF_ERROR_NOT_FOUND | |
1170 */ | |
1171 static int | |
1172 get_mech_name(const char *name, char **mech, char **val) | |
1173 { | |
1174 char *p; | |
1175 char *m; | |
1176 | |
1177 if ((m = strdup(name)) == NULL) { | |
1178 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1179 return (SCF_FAILED); | |
1180 } | |
1181 if ((p = strchr(m, ',')) == NULL) { | |
1182 free(m); | |
1183 (void) scf_set_error(SCF_ERROR_NOT_FOUND); | |
1184 return (SCF_FAILED); | |
1185 } | |
1186 *p = '\0'; | |
1187 *val = p + 1; | |
1188 *mech = m; | |
1189 | |
1190 return (SCF_SUCCESS); | |
1191 } | |
1192 | |
1193 /* | |
1194 * Return the number of transitions in a transition set. | |
1195 * If the transition set is invalid, it returns zero. | |
1196 */ | |
1197 static uint_t | |
1198 num_of_transitions(int32_t t) | |
1199 { | |
1200 int i; | |
1201 int n = 0; | |
1202 | |
1203 if (SCF_TRANS_VALID(t)) { | |
1204 for (i = 0x1; i < SCF_STATE_ALL; i <<= 1) { | |
1205 if (i & t) | |
1206 ++n; | |
1207 if (SCF_TRANS_INITIAL_STATE(t) & i) | |
1208 ++n; | |
1209 } | |
1210 } | |
1211 | |
1212 return (n); | |
1213 } | |
1214 | |
1215 /* | |
1216 * Return the SCF_STATE_* macro value for the state in the FMA classes for | |
1217 * SMF state transitions. They are of type: | |
1218 * SCF_SVC_TRANSITION_CLASS.<state> | |
1219 * ireport.os.smf.state-transition.<state> | |
1220 */ | |
1221 static int32_t | |
1222 class_to_transition(const char *c) | |
1223 { | |
1224 const char *p; | |
1225 int r = 0; | |
1226 size_t n; | |
1227 | |
1228 if (!is_svc_stn(c)) { | |
1229 return (0); | |
1230 } | |
1231 | |
1232 /* | |
1233 * if we get here, c is SCF_SVC_TRANSITION_CLASS or longer | |
1234 */ | |
1235 p = c + strlen(SCF_SVC_TRANSITION_CLASS); | |
1236 if (*p == '.') | |
1237 ++p; | |
1238 else | |
1239 return (0); | |
1240 | |
1241 if ((n = base_class_len(p)) == 0) | |
1242 return (0); | |
1243 | |
1244 if ((r = state_from_string(p, n)) == -1) | |
1245 r = 0; | |
1246 | |
1247 return (r); | |
1248 } | |
1249 | |
1250 /* | |
1251 * return SCF_SUCCESS or SCF_FAILED on | |
1252 * SCF_ERROR_BACKEND_ACCESS | |
1253 * SCF_ERROR_BACKEND_READONLY | |
1254 * SCF_ERROR_CONNECTION_BROKEN | |
1255 * SCF_ERROR_DELETED | |
1256 * SCF_ERROR_INTERNAL | |
1257 * SCF_ERROR_INVALID_ARGUMENT | |
1258 * SCF_ERROR_NO_MEMORY | |
1259 * SCF_ERROR_NO_RESOURCES | |
1260 * SCF_ERROR_NOT_FOUND | |
1261 * SCF_ERROR_PERMISSION_DENIED | |
1262 */ | |
1263 int | |
1264 smf_notify_set_params(const char *class, nvlist_t *attr) | |
1265 { | |
1266 uint32_t ver; | |
1267 int32_t tset; | |
1268 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); | |
1269 scf_error_t scf_e = scf_error(); | |
1270 scf_service_t *s = scf_service_create(h); | |
1271 scf_instance_t *i = scf_instance_create(h); | |
1272 scf_propertygroup_t *pg = scf_pg_create(h); | |
1273 nvlist_t *params = NULL; | |
1274 char *fmri = (char *)SCF_NOTIFY_PARAMS_INST; | |
1275 char *pgname = NULL; | |
1276 int r = SCF_FAILED; | |
1277 boolean_t is_stn; | |
1278 int j; | |
1279 | |
1280 assert(class != NULL); | |
1281 if (h == NULL) { | |
1282 /* | |
1283 * use saved error if _scf_handle_create_and_bind() fails | |
1284 */ | |
1285 (void) scf_set_error(scf_e); | |
1286 goto cleanup; | |
1287 } | |
1288 if (i == NULL || s == NULL || pg == NULL) | |
1289 goto cleanup; | |
1290 | |
1291 /* check version */ | |
1292 if (nvlist_lookup_uint32(attr, SCF_NOTIFY_NAME_VERSION, &ver) != 0 || | |
1293 ver != SCF_NOTIFY_PARAMS_VERSION) { | |
1294 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1295 goto cleanup; | |
1296 } | |
1297 | |
1298 if (nvlist_lookup_nvlist(attr, SCF_NOTIFY_PARAMS, ¶ms) != 0) { | |
1299 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1300 goto cleanup; | |
1301 } | |
1302 | |
1303 is_stn = is_svc_stn(class); | |
1304 /* special case SMF state transition notification */ | |
1305 if (is_stn && | |
1306 (nvlist_lookup_string(attr, SCF_NOTIFY_NAME_FMRI, &fmri) != 0 || | |
1307 nvlist_lookup_int32(attr, SCF_NOTIFY_NAME_TSET, &tset) != 0 || | |
1308 !SCF_TRANS_VALID(tset))) { | |
1309 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1310 goto cleanup; | |
1311 } | |
1312 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) | |
1313 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { | |
1314 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1315 } else if (check_scf_error(scf_error(), errs_1)) { | |
1316 goto cleanup; | |
1317 } | |
1318 | |
1319 if (is_stn) { | |
1320 tset |= class_to_transition(class); | |
1321 | |
1322 if (!SCF_TRANS_VALID(tset)) { | |
1323 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1324 goto cleanup; | |
1325 } | |
1326 | |
1327 for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) { | |
1328 /* if this transition is not in the tset, continue */ | |
1329 if (!(tset & st_pgnames[j].st_state)) | |
1330 continue; | |
1331 | |
1332 if (get_or_add_pg(s, i, st_pgnames[j].st_pgname, | |
1333 SCF_NOTIFY_PARAMS_PG_TYPE, 0, pg) != 0 && | |
1334 check_scf_error(scf_error(), errs_2)) | |
1335 goto cleanup; | |
1336 | |
1337 if (notify_set_params(pg, params) != 0) | |
1338 goto cleanup; | |
1339 } | |
1340 if (s == NULL) { | |
1341 /* We only need to refresh the instance */ | |
1342 if (_smf_refresh_instance_i(i) != 0 && | |
1343 check_scf_error(scf_error(), errs_1)) | |
1344 goto cleanup; | |
1345 } else { | |
1346 /* We have to refresh all instances in the service */ | |
1347 if (_smf_refresh_all_instances(s) != 0 && | |
1348 check_scf_error(scf_error(), errs_1)) | |
1349 goto cleanup; | |
1350 } | |
1351 } else { | |
1352 if ((pgname = class_to_pgname(class)) == NULL) | |
1353 goto cleanup; | |
1354 if (get_or_add_pg(s, i, pgname, SCF_GROUP_APPLICATION, 0, pg) != | |
1355 0) { | |
1356 if (check_scf_error(scf_error(), errs_2)) { | |
1357 goto cleanup; | |
1358 } | |
1359 } | |
1360 if (notify_set_params(pg, params) != 0) { | |
1361 goto cleanup; | |
1362 } | |
1363 if (_smf_refresh_instance_i(i) != 0 && | |
1364 check_scf_error(scf_error(), errs_1)) | |
1365 goto cleanup; | |
1366 } | |
1367 | |
1368 r = SCF_SUCCESS; | |
1369 cleanup: | |
1370 scf_instance_destroy(i); | |
1371 scf_service_destroy(s); | |
1372 scf_pg_destroy(pg); | |
1373 scf_handle_destroy(h); | |
1374 free(pgname); | |
1375 | |
1376 return (r); | |
1377 } | |
1378 | |
1379 /* | |
1380 * returns SCF_SUCCESS or SCF_FAILED on | |
1381 * SCF_ERROR_CONNECTION_BROKEN | |
1382 * SCF_ERROR_DELETED | |
1383 * SCF_ERROR_HANDLE_DESTROYED | |
1384 * SCF_ERROR_HANDLE_MISMATCH | |
1385 * SCF_ERROR_INVALID_ARGUMENT | |
1386 * SCF_ERROR_NO_MEMORY | |
1387 * SCF_ERROR_NO_RESOURCES | |
1388 * SCF_ERROR_NOT_BOUND | |
1389 * SCF_ERROR_NOT_FOUND | |
1390 * SCF_ERROR_NOT_SET | |
1391 * SCF_ERROR_PERMISSION_DENIED | |
1392 */ | |
1393 int | |
1394 _scf_notify_get_params(scf_propertygroup_t *pg, nvlist_t *params) | |
1395 { | |
1396 scf_handle_t *h = scf_pg_handle(pg); | |
1397 scf_error_t scf_e = scf_error(); | |
1398 scf_property_t *p = scf_property_create(h); | |
1399 scf_iter_t *it = scf_iter_create(h); | |
1400 int sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; | |
1401 char *name = malloc(sz); | |
1402 int r = SCF_FAILED; | |
1403 int err; | |
1404 | |
1405 if (h == NULL) { | |
1406 /* | |
1407 * Use the error stored in scf_e | |
1408 */ | |
1409 (void) scf_set_error(scf_e); | |
1410 goto cleanup; | |
1411 } | |
1412 if (it == NULL || p == NULL) | |
1413 goto cleanup; | |
1414 | |
1415 if (name == NULL) { | |
1416 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1417 goto cleanup; | |
1418 } | |
1419 | |
1420 if (scf_iter_pg_properties(it, pg) != SCF_SUCCESS) { | |
1421 if (check_scf_error(scf_error(), errs_1)) { | |
1422 goto cleanup; | |
1423 } | |
1424 } | |
1425 | |
1426 while ((err = scf_iter_next_property(it, p)) == 1) { | |
1427 nvlist_t *nvl; | |
1428 int nvl_new = 0; | |
1429 char *mech; | |
1430 char *val; | |
1431 | |
1432 if (scf_property_get_name(p, name, sz) == SCF_FAILED) { | |
1433 if (check_scf_error(scf_error(), errs_1)) { | |
1434 goto cleanup; | |
1435 } | |
1436 } | |
1437 | |
1438 if (get_mech_name(name, &mech, &val) != SCF_SUCCESS) { | |
1439 if (scf_error() == SCF_ERROR_NOT_FOUND) | |
1440 continue; | |
1441 goto cleanup; | |
1442 } | |
1443 | |
1444 if (nvlist_lookup_nvlist(params, mech, &nvl) != 0) { | |
1445 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { | |
1446 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1447 free(mech); | |
1448 goto cleanup; | |
1449 } | |
1450 nvl_new = 1; | |
1451 } | |
1452 | |
1453 if (add_prop_to_nvlist(p, val, nvl, 1) != SCF_SUCCESS) { | |
1454 if (check_scf_error(scf_error(), errs_2)) { | |
1455 free(mech); | |
1456 nvlist_free(nvl); | |
1457 goto cleanup; | |
1458 } | |
1459 } | |
1460 if (nvl_new) { | |
1461 if (nvlist_add_nvlist(params, mech, nvl) != 0) { | |
1462 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1463 free(mech); | |
1464 nvlist_free(nvl); | |
1465 goto cleanup; | |
1466 } | |
1467 nvlist_free(nvl); | |
1468 } | |
1469 | |
1470 free(mech); | |
1471 } | |
1472 | |
1473 if (err == 0) { | |
1474 r = SCF_SUCCESS; | |
1475 } else if (check_scf_error(scf_error(), errs_2)) { | |
1476 goto cleanup; | |
1477 } | |
1478 | |
1479 cleanup: | |
1480 scf_iter_destroy(it); | |
1481 scf_property_destroy(p); | |
1482 free(name); | |
1483 | |
1484 return (r); | |
1485 } | |
1486 | |
1487 /* | |
1488 * Look up pg containing an SMF state transition parameters. If it cannot find | |
1489 * the pg in the composed view of the instance, it will look in the global | |
1490 * instance for the system wide parameters. | |
1491 * Instance, service and global instance have to be passed by caller. | |
1492 * | |
1493 * returns SCF_SUCCESS or SCF_FAILED on | |
1494 * SCF_ERROR_BACKEND_ACCESS | |
1495 * SCF_ERROR_CONNECTION_BROKEN | |
1496 * SCF_ERROR_DELETED | |
1497 * SCF_ERROR_HANDLE_DESTROYED | |
1498 * SCF_ERROR_HANDLE_MISMATCH | |
1499 * SCF_ERROR_INTERNAL | |
1500 * SCF_ERROR_INVALID_ARGUMENT | |
1501 * SCF_ERROR_NO_MEMORY | |
1502 * SCF_ERROR_NO_RESOURCES | |
1503 * SCF_ERROR_NOT_BOUND | |
1504 * SCF_ERROR_NOT_FOUND | |
1505 * SCF_ERROR_NOT_SET | |
1506 */ | |
1507 static int | |
1508 get_stn_pg(scf_service_t *s, scf_instance_t *i, scf_instance_t *g, | |
1509 const char *pgname, scf_propertygroup_t *pg) | |
1510 { | |
1511 if (get_pg(s, i, pgname, pg, 1) == 0 || | |
1512 scf_error() == SCF_ERROR_NOT_FOUND && | |
1513 get_pg(NULL, g, pgname, pg, 0) == 0) | |
1514 return (SCF_SUCCESS); | |
1515 | |
1516 return (SCF_FAILED); | |
1517 } | |
1518 | |
1519 /* | |
1520 * Populates nvlist_t params with the source fmri for the pg | |
1521 * | |
1522 * return SCF_SUCCESS or SCF_FAILED on | |
1523 * SCF_ERROR_DELETED | |
1524 * SCF_ERROR_CONNECTION_BROKEN | |
1525 * SCF_ERROR_NO_MEMORY | |
1526 */ | |
1527 static int | |
1528 get_pg_source(scf_propertygroup_t *pg, nvlist_t *params) | |
1529 { | |
1530 size_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1; | |
1531 char *fmri = malloc(sz); | |
1532 char *p; | |
1533 int r = SCF_FAILED; | |
1534 | |
1535 if (fmri == NULL) { | |
1536 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1537 goto out; | |
1538 } | |
1539 | |
1540 if (scf_pg_to_fmri(pg, fmri, sz) == -1) { | |
1541 if (check_scf_error(scf_error(), errs_1)) { | |
1542 goto out; | |
1543 } | |
1544 } | |
1545 | |
1546 /* get rid of the properties part of the pg source */ | |
1547 if ((p = strrchr(fmri, ':')) != NULL && p > fmri) | |
1548 *(p - 1) = '\0'; | |
1549 if (nvlist_add_string(params, SCF_NOTIFY_PARAMS_SOURCE_NAME, fmri) != | |
1550 0) { | |
1551 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1552 goto out; | |
1553 } | |
1554 | |
1555 r = SCF_SUCCESS; | |
1556 out: | |
1557 free(fmri); | |
1558 return (r); | |
1559 } | |
1560 | |
1561 /* | |
1562 * Specialized function to get SMF state transition notification parameters | |
1563 * | |
1564 * return SCF_SUCCESS or SCF_FAILED on | |
1565 * SCF_ERROR_BACKEND_ACCESS | |
1566 * SCF_ERROR_CONNECTION_BROKEN | |
1567 * SCF_ERROR_DELETED | |
1568 * SCF_ERROR_INTERNAL | |
1569 * SCF_ERROR_INVALID_ARGUMENT | |
1570 * SCF_ERROR_NO_MEMORY | |
1571 * SCF_ERROR_NO_RESOURCES | |
1572 * SCF_ERROR_NOT_FOUND | |
1573 * SCF_ERROR_PERMISSION_DENIED | |
1574 */ | |
1575 int | |
1576 _scf_get_svc_notify_params(const char *fmri, nvlist_t *nvl, int32_t tset, | |
1577 int getsource, int getglobal) | |
1578 { | |
1579 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); | |
1580 scf_error_t scf_e = scf_error(); | |
1581 scf_service_t *s = scf_service_create(h); | |
1582 scf_instance_t *i = scf_instance_create(h); | |
1583 scf_instance_t *g = scf_instance_create(h); | |
1584 scf_propertygroup_t *pg = scf_pg_create(h); | |
1585 int r = SCF_FAILED; | |
1586 nvlist_t **params = NULL; | |
1587 uint_t c, nvl_num = 0; | |
1588 int not_found = 1; | |
1589 int j; | |
1590 const char *pgname; | |
1591 | |
1592 assert(fmri != NULL && nvl != NULL); | |
1593 if (h == NULL) { | |
1594 /* | |
1595 * use saved error if _scf_handle_create_and_bind() fails | |
1596 */ | |
1597 (void) scf_set_error(scf_e); | |
1598 goto cleanup; | |
1599 } | |
1600 if (s == NULL || i == NULL || g == NULL || pg == NULL) | |
1601 goto cleanup; | |
1602 | |
1603 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS || | |
1604 scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, g, NULL, | |
1605 NULL, SCF_DECODE_FMRI_EXACT) != 0) { | |
1606 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { | |
1607 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1608 } else if (check_scf_error(scf_error(), errs_1)) { | |
1609 goto cleanup; | |
1610 } | |
1611 } | |
1612 | |
1613 nvl_num = num_of_transitions(tset); | |
1614 if ((params = calloc(nvl_num, sizeof (nvlist_t *))) == NULL) { | |
1615 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1616 goto cleanup; | |
1617 } | |
1618 | |
1619 for (c = 0; c < nvl_num; ++c) | |
1620 if (nvlist_alloc(params + c, NV_UNIQUE_NAME, 0) != 0) { | |
1621 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1622 goto cleanup; | |
1623 } | |
1624 | |
1625 for (c = 0, j = 0; st_pgnames[j].st_pgname != NULL; ++j) { | |
1626 /* if this transition is not in the tset, continue */ | |
1627 if (!(tset & st_pgnames[j].st_state)) | |
1628 continue; | |
1629 | |
1630 assert(c < nvl_num); | |
1631 pgname = st_pgnames[j].st_pgname; | |
1632 | |
1633 if (nvlist_add_int32(params[c], SCF_NOTIFY_NAME_TSET, | |
1634 st_pgnames[j].st_state) != 0) { | |
1635 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1636 goto cleanup; | |
1637 } | |
1638 if ((getglobal ? get_stn_pg(s, i, g, pgname, pg) : | |
1639 get_pg(s, i, pgname, pg, 1)) == SCF_SUCCESS) { | |
1640 not_found = 0; | |
1641 if (_scf_notify_get_params(pg, params[c]) != | |
1642 SCF_SUCCESS) | |
1643 goto cleanup; | |
1644 if (getsource && get_pg_source(pg, params[c]) != | |
1645 SCF_SUCCESS) | |
1646 goto cleanup; | |
1647 } else if (scf_error() == SCF_ERROR_NOT_FOUND || | |
1648 scf_error() == SCF_ERROR_DELETED) { | |
1649 /* keep driving */ | |
1650 /*EMPTY*/ | |
1651 } else if (check_scf_error(scf_error(), errs_1)) { | |
1652 goto cleanup; | |
1653 } | |
1654 ++c; | |
1655 } | |
1656 | |
1657 if (not_found) { | |
1658 (void) scf_set_error(SCF_ERROR_NOT_FOUND); | |
1659 goto cleanup; | |
1660 } | |
1661 | |
1662 assert(c == nvl_num); | |
1663 | |
1664 if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, params, nvl_num) != | |
1665 0 || nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, | |
1666 SCF_NOTIFY_PARAMS_VERSION) != 0) { | |
1667 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1668 goto cleanup; | |
1669 } | |
1670 | |
1671 r = SCF_SUCCESS; | |
1672 | |
1673 cleanup: | |
1674 scf_pg_destroy(pg); | |
1675 scf_instance_destroy(i); | |
1676 scf_instance_destroy(g); | |
1677 scf_service_destroy(s); | |
1678 scf_handle_destroy(h); | |
1679 if (params != NULL) | |
1680 for (c = 0; c < nvl_num; ++c) | |
1681 nvlist_free(params[c]); | |
1682 free(params); | |
1683 | |
1684 return (r); | |
1685 } | |
1686 | |
1687 /* | |
1688 * Specialized function to get fma notification parameters | |
1689 * | |
1690 * return SCF_SUCCESS or SCF_FAILED on | |
1691 * SCF_ERROR_BACKEND_ACCESS | |
1692 * SCF_ERROR_CONNECTION_BROKEN | |
1693 * SCF_ERROR_DELETED | |
1694 * SCF_ERROR_INTERNAL | |
1695 * SCF_ERROR_INVALID_ARGUMENT | |
1696 * SCF_ERROR_NO_MEMORY | |
1697 * SCF_ERROR_NO_RESOURCES | |
1698 * SCF_ERROR_NOT_FOUND | |
1699 * SCF_ERROR_PERMISSION_DENIED | |
1700 */ | |
1701 int | |
1702 _scf_get_fma_notify_params(const char *class, nvlist_t *nvl, int getsource) | |
1703 { | |
1704 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); | |
1705 scf_error_t scf_e = scf_error(); | |
1706 scf_instance_t *i = scf_instance_create(h); | |
1707 scf_propertygroup_t *pg = scf_pg_create(h); | |
1708 int r = SCF_FAILED; | |
1709 nvlist_t *params = NULL; | |
1710 char *pgname = NULL; | |
1711 | |
1712 if (h == NULL) { | |
1713 /* | |
1714 * use saved error if _scf_handle_create_and_bind() fails | |
1715 */ | |
1716 (void) scf_set_error(scf_e); | |
1717 goto cleanup; | |
1718 } | |
1719 if (i == NULL || pg == NULL) | |
1720 goto cleanup; | |
1721 | |
1722 if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, NULL, i, | |
1723 NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { | |
1724 if (check_scf_error(scf_error(), errs_1)) { | |
1725 goto cleanup; | |
1726 } | |
1727 } | |
1728 | |
1729 if ((pgname = class_to_pgname(class)) == NULL) | |
1730 goto cleanup; | |
1731 | |
1732 while (get_pg(NULL, i, pgname, pg, 0) != 0) { | |
1733 if (scf_error() == SCF_ERROR_NOT_FOUND) { | |
1734 char *p = strrchr(pgname, '.'); | |
1735 | |
1736 if (p != NULL) { | |
1737 *p = ','; | |
1738 /* | |
1739 * since the resulting string is shorter, | |
1740 * there is no risk of buffer overflow | |
1741 */ | |
1742 (void) strcpy(p + 1, SCF_NOTIFY_PG_POSTFIX); | |
1743 continue; | |
1744 } | |
1745 } | |
1746 | |
1747 if (check_scf_error(scf_error(), errs_1)) { | |
1748 goto cleanup; | |
1749 } | |
1750 } | |
1751 | |
1752 if (nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0) { | |
1753 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1754 goto cleanup; | |
1755 } | |
1756 | |
1757 if (_scf_notify_get_params(pg, params) != SCF_SUCCESS) | |
1758 goto cleanup; | |
1759 | |
1760 if (getsource && get_pg_source(pg, params) != SCF_SUCCESS) | |
1761 goto cleanup; | |
1762 | |
1763 if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, ¶ms, 1) != 0 || | |
1764 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, | |
1765 SCF_NOTIFY_PARAMS_VERSION) != 0) { | |
1766 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1767 goto cleanup; | |
1768 } | |
1769 | |
1770 r = SCF_SUCCESS; | |
1771 | |
1772 cleanup: | |
1773 if (params) | |
1774 nvlist_free(params); | |
1775 scf_pg_destroy(pg); | |
1776 scf_instance_destroy(i); | |
1777 scf_handle_destroy(h); | |
1778 free(pgname); | |
1779 | |
1780 return (r); | |
1781 } | |
1782 | |
1783 /* | |
1784 * Retrieve the notification parameters for the Event described in the | |
1785 * input nvlist_t nvl. | |
1786 * The function will allocate an nvlist_t to store the notification | |
1787 * parameters. The notification parameters in the output nvlist will have | |
1788 * the following format: | |
1789 * | |
1790 * version (uint32_t) | |
1791 * SCF_NOTIFY_PARAMS (array of embedded nvlists) | |
1792 * (start of notify-params[0]) | |
1793 * tset (int32_t) | |
1794 * <mechanism-name> (embedded nvlist) | |
1795 * <parameter-name> <parameter-type> | |
1796 * ... | |
1797 * (end <mechanism-name>) | |
1798 * ... | |
1799 * (end of notify-params[0]) | |
1800 * ... | |
1801 * | |
1802 * return SCF_SUCCESS or SCF_FAILED on | |
1803 * SCF_ERROR_BACKEND_ACCESS | |
1804 * SCF_ERROR_CONNECTION_BROKEN | |
1805 * SCF_ERROR_DELETED | |
1806 * SCF_ERROR_INTERNAL | |
1807 * SCF_ERROR_INVALID_ARGUMENT | |
1808 * SCF_ERROR_NO_MEMORY | |
1809 * SCF_ERROR_NO_RESOURCES | |
1810 * SCF_ERROR_NOT_FOUND | |
1811 * SCF_ERROR_PERMISSION_DENIED | |
1812 */ | |
1813 int | |
1814 smf_notify_get_params(nvlist_t **params, nvlist_t *nvl) | |
1815 { | |
1816 char *class; | |
1817 char *from; /* from state */ | |
1818 char *to; /* to state */ | |
1819 nvlist_t *attr; | |
1820 char *fmri; | |
1821 int32_t tset = 0; | |
1822 int r = SCF_FAILED; | |
1823 | |
1824 if (params == NULL || nvlist_lookup_string(nvl, "class", &class) != 0) { | |
1825 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1826 return (r); | |
1827 } | |
1828 if (nvlist_alloc(params, NV_UNIQUE_NAME, 0) != 0) { | |
1829 (void) scf_set_error(SCF_ERROR_NO_MEMORY); | |
1830 return (r); | |
1831 } | |
1832 | |
1833 if (is_svc_stn(class)) { | |
1834 if (nvlist_lookup_nvlist(nvl, "attr", &attr) != 0 || | |
1835 nvlist_lookup_string(attr, "svc-string", &fmri) != 0 || | |
1836 nvlist_lookup_string(attr, "from-state", &from) != 0 || | |
1837 nvlist_lookup_string(attr, "to-state", &to) != 0) { | |
1838 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1839 goto cleanup; | |
1840 } | |
1841 | |
1842 tset = SCF_TRANS(smf_state_from_string(from), | |
1843 smf_state_from_string(to)); | |
1844 if (!SCF_TRANS_VALID(tset)) { | |
1845 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1846 goto cleanup; | |
1847 } | |
1848 tset |= class_to_transition(class); | |
1849 | |
1850 r = _scf_get_svc_notify_params(fmri, *params, tset, 0, 1); | |
1851 } else { | |
1852 r = _scf_get_fma_notify_params(class, *params, 0); | |
1853 } | |
1854 | |
1855 cleanup: | |
1856 if (r == SCF_FAILED) { | |
1857 nvlist_free(*params); | |
1858 *params = NULL; | |
1859 } | |
1860 | |
1861 return (r); | |
1862 } | |
1863 | |
1864 /* | |
1865 * return SCF_SUCCESS or SCF_FAILED on | |
1866 * SCF_ERROR_BACKEND_ACCESS | |
1867 * SCF_ERROR_BACKEND_READONLY | |
1868 * SCF_ERROR_CONNECTION_BROKEN | |
1869 * SCF_ERROR_DELETED | |
1870 * SCF_ERROR_INTERNAL | |
1871 * SCF_ERROR_INVALID_ARGUMENT | |
1872 * SCF_ERROR_NO_MEMORY | |
1873 * SCF_ERROR_NO_RESOURCES | |
1874 * SCF_ERROR_NOT_FOUND | |
1875 * SCF_ERROR_PERMISSION_DENIED | |
1876 */ | |
1877 int | |
1878 smf_notify_del_params(const char *class, const char *fmri, int32_t tset) | |
1879 { | |
1880 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION); | |
1881 scf_error_t scf_e = scf_error(); | |
1882 scf_service_t *s = scf_service_create(h); | |
1883 scf_instance_t *i = scf_instance_create(h); | |
1884 scf_propertygroup_t *pg = scf_pg_create(h); | |
1885 int r = SCF_FAILED; | |
1886 char *pgname = NULL; | |
1887 int j; | |
1888 | |
1889 if (class == NULL) { | |
1890 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1891 goto cleanup; | |
1892 } | |
1893 | |
1894 if (h == NULL) { | |
1895 /* | |
1896 * use saved error if _scf_handle_create_and_bind() fails | |
1897 */ | |
1898 (void) scf_set_error(scf_e); | |
1899 goto cleanup; | |
1900 } | |
1901 if (s == NULL || i == NULL || pg == NULL) | |
1902 goto cleanup; | |
1903 | |
1904 if (is_svc_stn(class)) { | |
1905 tset |= class_to_transition(class); | |
1906 | |
1907 if (!SCF_TRANS_VALID(tset) || fmri == NULL) { | |
1908 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); | |
1909 goto cleanup; | |
1910 } | |
1911 | |
1912 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) { | |
1913 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) | |
1914 (void) scf_set_error( | |
1915 SCF_ERROR_INVALID_ARGUMENT); | |
1916 if (check_scf_error(scf_error(), errs_1)) { | |
1917 goto cleanup; | |
1918 } | |
1919 } | |
1920 | |
1921 for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) { | |
1922 /* if this transition is not in the tset, continue */ | |
1923 if (!(tset & st_pgnames[j].st_state)) | |
1924 continue; | |
1925 | |
1926 if (del_pg(s, i, st_pgnames[j].st_pgname, pg) != | |
1927 SCF_SUCCESS && | |
1928 scf_error() != SCF_ERROR_DELETED && | |
1929 scf_error() != SCF_ERROR_NOT_FOUND) { | |
1930 if (check_scf_error(scf_error(), | |
1931 errs_1)) { | |
1932 goto cleanup; | |
1933 } | |
1934 } | |
1935 } | |
1936 if (s == NULL) { | |
1937 /* We only need to refresh the instance */ | |
1938 if (_smf_refresh_instance_i(i) != 0 && | |
1939 check_scf_error(scf_error(), errs_1)) | |
1940 goto cleanup; | |
1941 } else { | |
1942 /* We have to refresh all instances in the service */ | |
1943 if (_smf_refresh_all_instances(s) != 0 && | |
1944 check_scf_error(scf_error(), errs_1)) | |
1945 goto cleanup; | |
1946 } | |
1947 } else { | |
1948 if ((pgname = class_to_pgname(class)) == NULL) | |
1949 goto cleanup; | |
1950 | |
1951 if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, | |
1952 NULL, i, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) | |
1953 goto cleanup; | |
1954 | |
1955 if (del_pg(NULL, i, pgname, pg) != SCF_SUCCESS && | |
1956 scf_error() != SCF_ERROR_DELETED && | |
1957 scf_error() != SCF_ERROR_NOT_FOUND) { | |
1958 if (check_scf_error(scf_error(), errs_1)) { | |
1959 goto cleanup; | |
1960 } | |
1961 } | |
1962 | |
1963 if (_smf_refresh_instance_i(i) != 0 && | |
1964 check_scf_error(scf_error(), errs_1)) | |
1965 goto cleanup; | |
1966 } | |
1967 | |
1968 | |
1969 r = SCF_SUCCESS; | |
1970 | |
1971 cleanup: | |
1972 scf_pg_destroy(pg); | |
1973 scf_instance_destroy(i); | |
1974 scf_service_destroy(s); | |
1975 scf_handle_destroy(h); | |
1976 free(pgname); | |
1977 | |
1978 return (r); | |
1979 } |