Print this page
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/syseventd/modules/sysevent_conf_mod/sysevent_conf_mod.c
+++ new/usr/src/cmd/syseventd/modules/sysevent_conf_mod/sysevent_conf_mod.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * sysevent_conf_mod - syseventd daemon sysevent.conf module
28 28 *
29 29 * This module provides a configuration file registration
30 30 * mechanism whereby event producers can define an event
31 31 * specification to be matched against events, with an
32 32 * associated command line to be invoked for each matching event.
33 33 * It includes a simple macro capability for flexibility in
34 34 * generating arbitrary command line formats from event-associated
35 35 * data, and a user specification so that commands can be invoked
36 36 * with reduced privileges to eliminate a security risk.
37 37 *
38 38 * sysevent.conf files contain event specifications and associated
39 39 * command path and optional arguments. System events received
40 40 * from the kernel by the sysevent daemon, syseventd, are
41 41 * compared against the event specifications in the sysevent.conf
42 42 * files. The command as specified by pathname and arguments
43 43 * is invoked for each matching event.
44 44 *
45 45 * All sysevent.conf files reside in /etc/sysevent/config.
46 46 *
47 47 */
48 48
49 49
50 50 #include <stdio.h>
51 51
52 52 #include <unistd.h>
53 53 #include <stdarg.h>
54 54 #include <stdlib.h>
55 55 #include <string.h>
56 56 #include <strings.h>
57 57 #include <limits.h>
58 58 #include <thread.h>
59 59 #include <synch.h>
60 60 #include <errno.h>
61 61 #include <fcntl.h>
62 62 #include <ctype.h>
63 63 #include <pwd.h>
64 64 #include <syslog.h>
65 65 #include <sys/types.h>
66 66 #include <sys/stat.h>
67 67 #include <sys/sunddi.h>
68 68 #include <sys/sysevent.h>
69 69 #include <libsysevent.h>
70 70 #include <libnvpair.h>
71 71 #include <dirent.h>
72 72 #include <locale.h>
73 73 #include <signal.h>
74 74 #include <wait.h>
75 75
76 76 #include "syseventd.h"
77 77 #include "syseventconfd_door.h"
78 78 #include "sysevent_conf_mod.h"
79 79 #include "message_conf_mod.h"
80 80
81 81
82 82 static char *whoami = "sysevent_conf_mod";
83 83
84 84 /*
85 85 * Event sequencing, time stamp and retry count
86 86 */
87 87 static int ev_nretries; /* retry count per event */
88 88 static uint64_t ev_seq; /* current event sequencing number */
89 89 static hrtime_t ev_ts; /* current event timestamp */
90 90 static int first_event; /* first event since init */
91 91
92 92 /*
93 93 * State of the sysevent conf table, derived from
94 94 * the /etc/sysevent/config files
95 95 */
96 96 static conftab_t *conftab = NULL;
97 97 static syseventtab_t *syseventtab = NULL;
98 98 static syseventtab_t *syseventtab_tail = NULL;
99 99 static sysevent_handle_t *confd_handle = NULL;
100 100
101 101 /*
102 102 * The cmd queue is a queue of commands ready to be sent
103 103 * to syseventconfd. Each command consists of the path
104 104 * and arguments to be fork/exec'ed. The daemon is unable
105 105 * to handle events during an active fork/exec and returns
106 106 * EAGAIN as a result. It is grossly inefficient to bounce
107 107 * these events back to syseventd, so we queue them here for delivery.
108 108 */
109 109 static cmdqueue_t *cmdq = NULL;
110 110 static cmdqueue_t *cmdq_tail = NULL;
111 111 static mutex_t cmdq_lock;
112 112 static cond_t cmdq_cv;
113 113 static int cmdq_cnt;
114 114 static thread_t cmdq_thr_id;
115 115 static cond_t cmdq_thr_cv;
116 116 static int want_fini;
117 117
118 118 /*
119 119 * State of the door channel to syseventconfd
120 120 */
121 121 static int confd_state = CONFD_STATE_NOT_RUNNING;
122 122
123 123 /*
124 124 * Number of times to retry event after restarting syeventconfd
125 125 */
126 126 static int confd_retries;
127 127
128 128 /*
129 129 * Number of times to retry a failed transport
130 130 */
131 131 static int transport_retries;
132 132
133 133 /*
134 134 * Normal sleep time when syseventconfd returns EAGAIN
135 135 * is one second but to avoid thrashing, sleep for
136 136 * something larger when syseventconfd not responding.
137 137 * This should never happen of course but it seems better
138 138 * to attempt to handle possible errors gracefully.
139 139 */
140 140 static int confd_err_msg_emitted;
141 141
142 142
143 143 static int sysevent_conf_dummy_event(sysevent_t *, int);
144 144
145 145 /*
146 146 * External references
147 147 */
148 148 extern int debug_level;
149 149 extern char *root_dir;
150 150 extern void syseventd_print(int level, char *format, ...);
151 151 extern void syseventd_err_print(char *format, ...);
152 152
153 153
154 154
155 155 static struct slm_mod_ops sysevent_conf_mod_ops = {
156 156 SE_MAJOR_VERSION, /* syseventd module major version */
157 157 SE_MINOR_VERSION, /* syseventd module minor version */
158 158 SE_MAX_RETRY_LIMIT, /* max retry if EAGAIN */
159 159 &sysevent_conf_event /* event handler */
160 160 };
161 161
162 162 static struct slm_mod_ops sysevent_conf_dummy_mod_ops = {
163 163 SE_MAJOR_VERSION, /* syseventd module major version */
164 164 SE_MINOR_VERSION, /* syseventd module minor version */
165 165 0, /* no retries, always succeeds */
166 166 &sysevent_conf_dummy_event /* dummy event handler */
167 167 };
168 168
169 169
170 170
171 171 /*
172 172 * skip_spaces() - skip to next non-space character
173 173 */
174 174 static char *
175 175 skip_spaces(char **cpp)
176 176 {
177 177 char *cp = *cpp;
178 178
179 179 while (*cp == ' ' || *cp == '\t')
180 180 cp++;
181 181 if (*cp == 0) {
182 182 *cpp = 0;
183 183 return (NULL);
184 184 }
185 185 return (cp);
186 186 }
187 187
188 188
189 189 /*
190 190 * Get next white-space separated field.
191 191 * next_field() will not check any characters on next line.
192 192 * Each entry is composed of a single line.
193 193 */
194 194 static char *
195 195 next_field(char **cpp)
196 196 {
197 197 char *cp = *cpp;
198 198 char *start;
199 199
200 200 while (*cp == ' ' || *cp == '\t')
201 201 cp++;
202 202 if (*cp == 0) {
203 203 *cpp = 0;
204 204 return (NULL);
205 205 }
206 206 start = cp;
207 207 while (*cp && *cp != ' ' && *cp != '\t')
208 208 cp++;
209 209 if (*cp != 0)
210 210 *cp++ = 0;
211 211 *cpp = cp;
212 212 return (start);
213 213 }
214 214
215 215
216 216
217 217 /*
218 218 * The following functions are simple wrappers/equivalents
219 219 * for malloc, realloc, free, strdup and a special free
220 220 * for strdup.
221 221 *
222 222 * These functions ensure that any failed mallocs are
223 223 * reported via syslog() so if a command is not evoked
224 224 * in response to an event, the reason should be logged.
225 225 * These functions also provide a convenient place for
226 226 * hooks for checking for memory leaks.
227 227 */
228 228
229 229 static void *
230 230 sc_malloc(size_t n)
231 231 {
232 232 void *p;
233 233
234 234 p = malloc(n);
235 235 if (p == NULL) {
236 236 syslog(LOG_ERR, OUT_OF_MEMORY_ERR);
237 237 }
238 238 return (p);
239 239 }
240 240
241 241 /*ARGSUSED*/
242 242 static void *
243 243 sc_realloc(void *p, size_t current, size_t n)
244 244 {
245 245 p = realloc(p, n);
246 246 if (p == NULL) {
247 247 syslog(LOG_ERR, OUT_OF_MEMORY_ERR);
248 248 }
249 249 return (p);
250 250 }
251 251
252 252
253 253 /*ARGSUSED*/
254 254 static void
255 255 sc_free(void *p, size_t n)
256 256 {
257 257 free(p);
258 258 }
259 259
260 260
261 261 static char *
262 262 sc_strdup(char *cp)
263 263 {
264 264 char *new;
265 265
266 266 new = malloc((unsigned)(strlen(cp) + 1));
267 267 if (new == NULL) {
268 268 syslog(LOG_ERR, OUT_OF_MEMORY_ERR);
269 269 return (NULL);
270 270 }
271 271 (void) strcpy(new, cp);
272 272 return (new);
273 273 }
274 274
275 275
276 276 static void
277 277 sc_strfree(char *s)
278 278 {
279 279 if (s)
280 280 free(s);
281 281 }
282 282
283 283
284 284 /*
285 285 * The following functions provide some simple dynamic string
286 286 * capability. This module has no hard-coded maximum string
287 287 * lengths and should be able to parse and generate arbitrarily
288 288 * long strings, macro expansion and command lines.
289 289 *
290 290 * Each string must be explicitly allocated and freed.
291 291 */
292 292
293 293 /*
294 294 * Allocate a dynamic string, with a hint to indicate how
295 295 * much memory to dynamically add to the string as it grows
296 296 * beyond its existing bounds, so as to avoid excessive
297 297 * reallocs as a string grows.
298 298 */
299 299 static str_t *
300 300 initstr(int hint)
301 301 {
302 302 str_t *str;
303 303
304 304 if ((str = sc_malloc(sizeof (str_t))) == NULL)
305 305 return (NULL);
306 306 str->s_str = NULL;
307 307 str->s_len = 0;
308 308 str->s_alloc = 0;
309 309 str->s_hint = hint;
310 310 return (str);
311 311 }
312 312
313 313
314 314 /*
315 315 * Free a dynamically-allocated string
316 316 */
317 317 static void
318 318 freestr(str_t *str)
319 319 {
320 320 if (str->s_str) {
321 321 sc_free(str->s_str, str->s_alloc);
322 322 }
323 323 sc_free(str, sizeof (str_t));
324 324 }
325 325
326 326
327 327 /*
328 328 * Reset a dynamically-allocated string, allows reuse
329 329 * rather than freeing the old and allocating a new one.
330 330 */
331 331 static void
332 332 resetstr(str_t *str)
333 333 {
334 334 str->s_len = 0;
335 335 }
336 336
337 337
338 338 /*
339 339 * Copy a (simple) string onto a dynamically-allocated string
340 340 */
341 341 static int
342 342 strcopys(str_t *str, char *s)
343 343 {
344 344 char *new_str;
345 345 int len = strlen(s) + 1;
346 346
347 347 if (str->s_alloc < len) {
348 348 new_str = (str->s_str == NULL) ?
349 349 sc_malloc(len+str->s_hint) :
350 350 sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
351 351 if (new_str == NULL) {
352 352 return (1);
353 353 }
354 354 str->s_str = new_str;
355 355 str->s_alloc = len + str->s_hint;
356 356 }
357 357 (void) strcpy(str->s_str, s);
358 358 str->s_len = len - 1;
359 359 return (0);
360 360 }
361 361
362 362
363 363 /*
364 364 * Concatenate a (simple) string onto a dynamically-allocated string
365 365 */
366 366 static int
367 367 strcats(str_t *str, char *s)
368 368 {
369 369 char *new_str;
370 370 int len = str->s_len + strlen(s) + 1;
371 371
372 372 if (str->s_alloc < len) {
373 373 new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
374 374 sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
375 375 if (new_str == NULL) {
376 376 return (1);
377 377 }
378 378 str->s_str = new_str;
379 379 str->s_alloc = len + str->s_hint;
380 380 }
381 381 (void) strcpy(str->s_str + str->s_len, s);
382 382 str->s_len = len - 1;
383 383 return (0);
384 384 }
385 385
386 386
387 387 /*
388 388 * Concatenate a character onto a dynamically-allocated string
389 389 */
390 390 static int
391 391 strcatc(str_t *str, int c)
392 392 {
393 393 char *new_str;
394 394 int len = str->s_len + 2;
395 395
396 396 if (str->s_alloc < len) {
397 397 new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
398 398 sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
399 399 if (new_str == NULL) {
400 400 return (1);
401 401 }
402 402 str->s_str = new_str;
403 403 str->s_alloc = len + str->s_hint;
404 404 }
405 405 *(str->s_str + str->s_len) = (char)c;
406 406 *(str->s_str + str->s_len + 1) = 0;
407 407 str->s_len++;
408 408 return (0);
409 409 }
410 410
411 411 /*
412 412 * fgets() equivalent using a dynamically-allocated string
413 413 */
414 414 static char *
415 415 fstrgets(str_t *line, FILE *fp)
416 416 {
417 417 int c;
418 418
419 419 resetstr(line);
420 420 while ((c = fgetc(fp)) != EOF) {
421 421 if (strcatc(line, c))
422 422 return (NULL);
423 423 if (c == '\n')
424 424 break;
425 425 }
426 426 if (line->s_len == 0)
427 427 return (NULL);
428 428 return (line->s_str);
429 429 }
430 430
431 431 /*
432 432 * Truncate a dynamically-allocated string at index position 'pos'
433 433 */
434 434 static void
435 435 strtrunc(str_t *str, int pos)
436 436 {
437 437 if (str->s_len > pos) {
438 438 str->s_len = pos;
439 439 *(str->s_str + pos) = 0;
440 440 }
441 441 }
442 442
443 443
444 444
445 445 /*
446 446 * Parse a sysevent.conf file, adding each entry spec to the event table.
447 447 *
448 448 * The format of an entry in a sysevent.conf file is:
449 449 *
450 450 * class subclass vendor publisher user reserved1 reserved path arguments
451 451 *
452 452 * Fields are separated by either SPACE or TAB characters. A
453 453 * '#' (number sign) at the beginning of a line indicates a
454 454 * comment. Comment lines and blank lines are ignored.
455 455 *
456 456 * class
457 457 * The class of the event.
458 458 *
459 459 * subclass
460 460 * The subclass of the event.
461 461 *
462 462 * vendor
463 463 * The name of the vendor defining the event, usually the
464 464 * stock symbol. Events generated by system components
465 465 * provided by Sun Microsystems, Inc. always define vendor
466 466 * as 'SUNW'.
467 467 *
468 468 * publisher
469 469 * The name of the application, driver or system module
470 470 * producing the event.
471 471 *
472 472 * user
473 473 * The name of the user under which the command should be
474 474 * run. This allows commands to run with access privileges
475 475 * other than those for root. The user field should be '-'
476 476 * for commands to be run as root.
477 477 *
478 478 * reserved1
479 479 * Must be '-'.
480 480 *
481 481 * reserved2
482 482 * Must be '-'.
483 483 *
484 484 * path
485 485 * Pathname of the command to be invoked for matching events.
486 486 *
487 487 * arguments
488 488 * Optional argument with possible macro substitution to permit
489 489 * arbitrary command line construction with event-specific data.
490 490 */
491 491 static void
492 492 parse_conf_file(char *conf_file)
493 493 {
494 494 char conf_path[PATH_MAX];
495 495 FILE *fp;
496 496 char *lp;
497 497 str_t *line;
498 498 int lineno = 0;
499 499 char *vendor, *publisher;
500 500 char *class, *subclass;
501 501 char *user;
502 502 char *reserved1, *reserved2;
503 503 char *path, *args;
504 504 syseventtab_t *sep;
505 505 struct passwd pwd;
506 506 struct passwd *pwdp;
507 507 char pwdbuf[1024];
508 508 int do_setuid;
509 509 pid_t saved_uid;
510 510 gid_t saved_gid;
511 511 int i, err;
512 512
513 513 (void) snprintf(conf_path, PATH_MAX, "%s/%s",
514 514 SYSEVENT_CONFIG_DIR, conf_file);
515 515
516 516 syseventd_print(DBG_CONF_FILE, "%s: reading %s\n", whoami, conf_path);
517 517
518 518 if ((fp = fopen(conf_path, "r")) == NULL) {
519 519 syslog(LOG_ERR, CANNOT_OPEN_ERR, conf_file, strerror(errno));
520 520 return;
521 521 }
522 522
523 523 if ((line = initstr(128)) == NULL)
524 524 return;
525 525
526 526 while ((lp = fstrgets(line, fp)) != NULL) {
527 527 lineno++;
528 528 if (*lp == '\n' || *lp == '#')
529 529 continue;
530 530 *(lp + strlen(lp)-1) = 0;
531 531
532 532 syseventd_print(DBG_CONF_FILE, "[%d]: %s\n",
533 533 lineno, lp);
534 534
535 535 if ((class = next_field(&lp)) == NULL)
536 536 goto mal_formed;
537 537 if ((subclass = next_field(&lp)) == NULL)
538 538 goto mal_formed;
539 539 if ((vendor = next_field(&lp)) == NULL)
540 540 goto mal_formed;
541 541 if ((publisher = next_field(&lp)) == NULL)
542 542 goto mal_formed;
543 543 if ((user = next_field(&lp)) == NULL)
544 544 goto mal_formed;
545 545 if ((reserved1 = next_field(&lp)) == NULL)
546 546 goto mal_formed;
547 547 if ((reserved2 = next_field(&lp)) == NULL)
548 548 goto mal_formed;
549 549 if ((path = next_field(&lp)) == NULL)
550 550 goto mal_formed;
551 551 args = skip_spaces(&lp);
552 552
553 553 /*
554 554 * validate user
555 555 */
556 556 do_setuid = 0;
557 557 if ((strcmp(user, "-") != 0) && (strcmp(user, "root") != 0)) {
558 558 i = getpwnam_r(user, &pwd, pwdbuf,
559 559 sizeof (pwdbuf), &pwdp);
560 560 if (i != 0 || pwdp == NULL) {
561 561 syslog(LOG_ERR, NO_USER_ERR,
562 562 conf_file, lineno, user);
563 563 continue;
564 564 }
565 565 do_setuid = 1;
566 566 }
567 567
568 568 /*
569 569 * validate reserved fields
570 570 */
571 571 if (strcmp(reserved1, "-") != 0) {
572 572 syslog(LOG_ERR, RESERVED_FIELD_ERR,
573 573 conf_file, lineno, reserved1);
574 574 continue;
575 575 }
576 576 if (strcmp(reserved2, "-") != 0) {
577 577 syslog(LOG_ERR, RESERVED_FIELD_ERR,
578 578 conf_file, lineno, reserved2);
579 579 continue;
580 580 }
581 581
582 582 /*
583 583 * ensure path is executable by user
584 584 */
585 585 err = 0;
586 586 if (do_setuid) {
587 587 saved_uid = getuid();
588 588 saved_gid = getgid();
589 589 if (setregid(pwdp->pw_gid, -1) == -1) {
590 590 syslog(LOG_ERR, SETREGID_ERR,
591 591 whoami, pwdp->pw_gid, strerror(errno));
592 592 err = -1;
593 593 }
594 594 if (setreuid(pwdp->pw_uid, -1) == -1) {
595 595 syslog(LOG_ERR, SETREUID_ERR,
596 596 whoami, pwdp->pw_uid, strerror(errno));
597 597 err = -1;
598 598 }
599 599 }
600 600 if ((i = access(path, X_OK)) == -1) {
601 601 syslog(LOG_ERR, CANNOT_EXECUTE_ERR,
602 602 conf_file, lineno, path, strerror(errno));
603 603 }
604 604 if (do_setuid) {
605 605 if (setreuid(saved_uid, -1) == -1) {
606 606 syslog(LOG_ERR, SETREUID_ERR,
607 607 whoami, saved_uid, strerror(errno));
608 608 err = -1;
609 609 }
610 610 if (setregid(saved_gid, -1) == -1) {
611 611 syslog(LOG_ERR, SETREGID_ERR,
612 612 whoami, saved_gid, strerror(errno));
613 613 err = -1;
614 614 }
615 615 }
616 616 if (i == -1 || err == -1)
617 617 continue;
618 618
619 619 /*
620 620 * all sanity tests successful - perform allocations
621 621 * to add entry to table
622 622 */
623 623 if ((sep = sc_malloc(sizeof (syseventtab_t))) == NULL)
624 624 break;
625 625
626 626 sep->se_conf_file = conf_file;
627 627 sep->se_lineno = lineno;
628 628 sep->se_vendor = sc_strdup(vendor);
629 629 sep->se_publisher = sc_strdup(publisher);
630 630 sep->se_class = sc_strdup(class);
631 631 sep->se_subclass = sc_strdup(subclass);
632 632 sep->se_user = sc_strdup(user);
633 633 if (do_setuid) {
634 634 sep->se_uid = pwdp->pw_uid;
635 635 sep->se_gid = pwdp->pw_gid;
636 636 } else {
637 637 sep->se_uid = 0;
638 638 sep->se_gid = 0;
639 639 }
640 640 sep->se_reserved1 = sc_strdup(reserved1);
641 641 sep->se_reserved2 = sc_strdup(reserved2);
642 642 sep->se_path = sc_strdup(path);
643 643 sep->se_args = (args == NULL) ? NULL : sc_strdup(args);
644 644 sep->se_next = NULL;
645 645
646 646 if (sep->se_vendor == NULL || sep->se_publisher == NULL ||
647 647 sep->se_class == NULL || sep->se_subclass == NULL ||
648 648 sep->se_user == NULL || sep->se_reserved1 == NULL ||
649 649 sep->se_reserved2 == NULL || sep->se_path == NULL ||
650 650 (args && sep->se_args == NULL)) {
651 651 sc_strfree(sep->se_vendor);
652 652 sc_strfree(sep->se_publisher);
653 653 sc_strfree(sep->se_class);
654 654 sc_strfree(sep->se_subclass);
655 655 sc_strfree(sep->se_user);
656 656 sc_strfree(sep->se_reserved1);
657 657 sc_strfree(sep->se_reserved2);
658 658 sc_strfree(sep->se_path);
659 659 sc_strfree(sep->se_args);
660 660 sc_free(sep, sizeof (syseventtab_t));
661 661 break;
662 662 }
663 663
664 664 /*
665 665 * link new entry into the table
666 666 */
667 667 if (syseventtab == NULL) {
668 668 syseventtab = sep;
669 669 syseventtab_tail = sep;
670 670 } else {
671 671 syseventtab_tail->se_next = sep;
672 672 syseventtab_tail = sep;
673 673 }
674 674
675 675 if (debug_level >= DBG_DETAILED) {
676 676 syseventtab_t *sp;
677 677 for (sp = syseventtab; sp; sp = sp->se_next) {
678 678 syseventd_print(DBG_DETAILED,
679 679 " vendor=%s\n", sp->se_vendor);
680 680 syseventd_print(DBG_DETAILED,
681 681 " publisher=%s\n", sp->se_publisher);
682 682 syseventd_print(DBG_DETAILED,
683 683 " class=%s\n", sp->se_class);
684 684 syseventd_print(DBG_DETAILED,
685 685 " subclass=%s\n", sp->se_subclass);
686 686 syseventd_print(DBG_DETAILED,
687 687 " user=%s uid=%d gid=%d\n",
688 688 sp->se_user, sp->se_uid, sp->se_gid);
689 689 syseventd_print(DBG_DETAILED,
690 690 " reserved1=%s\n", sp->se_reserved1);
691 691 syseventd_print(DBG_DETAILED,
692 692 " reserved2=%s\n", sp->se_reserved2);
693 693 syseventd_print(DBG_DETAILED,
694 694 " path=%s\n", sp->se_path);
695 695 if (sp->se_args != NULL) {
696 696 syseventd_print(DBG_DETAILED,
697 697 " args=%s\n", sp->se_args);
698 698 }
699 699 }
700 700 }
701 701
702 702 continue;
703 703
704 704 mal_formed:
705 705 syslog(LOG_ERR, SYNTAX_ERR, conf_file, lineno);
706 706 }
707 707
708 708 freestr(line);
709 709 (void) fclose(fp);
710 710 }
711 711
712 712
713 713 /*
714 714 * Build the events specification table, a summation of all
715 715 * event specification found in the installed sysevent.conf
716 716 * configuration files.
717 717 *
718 718 * All sysevent.conf files reside in the /etc/sysevent/config
719 719 * and may contain zero or more event/command specifications.
720 720 * A sysevent.conf file should be named as follows:
721 721 *
722 722 * <vendor>,[<publisher>,][<class>,]sysevent.conf
723 723 *
724 724 * Event/command specifications delivered by the base Solaris
725 725 * system are provided in /etc/sysevent/config/SUNW,sysevent.conf.
726 726 * Event/command specifications delivered by optional
727 727 * Sun-supplied packages may install additional sysevent.conf
728 728 * files in /etc/sysevent/config using vendor SUNW, and additional
729 729 * publisher and/or event class naming to distinguish the
730 730 * events required for those products. Products provided
731 731 * by third-party hardware or software companies may
732 732 * distinguish their sysevent.conf files by vendor, and
733 733 * by publisher and/or event class within vendor.
734 734 *
735 735 * Files residing in /etc/sysevent/config with a '.' (period)
736 736 * as the first character of the name and files with a suffix
737 737 * of other than "sysevent.conf" are ignored.
738 738 */
739 739 static void
740 740 build_event_table()
741 741 {
742 742 conftab_t *cfp = NULL;
743 743 DIR *dir;
744 744 struct dirent *result;
745 745 conftab_t *new_cfp;
746 746 char *str;
747 747
748 748 if ((dir = opendir(SYSEVENT_CONFIG_DIR)) == NULL) {
749 749 syslog(LOG_ERR, CANNOT_OPEN_ERR,
750 750 SYSEVENT_CONFIG_DIR, strerror(errno));
751 751 return;
752 752 }
753 753
754 754 while ((result = readdir(dir)) != NULL) {
755 755 if (result->d_name[0] == '.')
756 756 continue;
757 757
758 758 /*
759 759 * file must have extension "sysevent.conf"
760 760 */
761 761 if ((str = strrchr(result->d_name, ',')) != NULL) {
762 762 str++;
763 763 } else {
764 764 str = result->d_name;
765 765 }
766 766 if (strcmp(str, "sysevent.conf") != 0) {
767 767 syseventd_print(DBG_CONF_FILE,
768 768 "%s: ignoring %s\n", whoami, str);
769 769 continue;
770 770 }
771 771
772 772 /*
773 773 * Add to file table and parse this conf file
774 774 */
775 775 if ((str = sc_strdup(result->d_name)) == NULL)
776 776 goto err;
777 777 if ((new_cfp = sc_malloc(sizeof (conftab_t))) == NULL) {
778 778 sc_strfree(str);
779 779 goto err;
780 780 }
781 781 if (conftab == NULL) {
782 782 conftab = new_cfp;
783 783 } else {
784 784 for (cfp = conftab; cfp->cf_next; cfp = cfp->cf_next)
785 785 ;
786 786 cfp->cf_next = new_cfp;
787 787 }
788 788 cfp = new_cfp;
789 789 cfp->cf_conf_file = str;
790 790 cfp->cf_next = NULL;
791 791
792 792 parse_conf_file(cfp->cf_conf_file);
793 793 }
794 794
795 795 err:
796 796 if (closedir(dir) == -1) {
797 797 if (errno == EAGAIN)
798 798 goto err;
799 799 syslog(LOG_ERR, CLOSEDIR_ERR,
800 800 SYSEVENT_CONFIG_DIR, strerror(errno));
801 801 }
802 802 }
803 803
804 804
805 805 static int
806 806 enter_lock(char *lock_file)
807 807 {
808 808 struct flock lock;
809 809 int lock_fd;
810 810
811 811 (void) strlcpy(lock_file, LOCK_FILENAME, PATH_MAX);
812 812 lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
813 813 if (lock_fd < 0) {
814 814 syslog(LOG_ERR, MSG_LOCK_CREATE_ERR,
815 815 whoami, lock_file, strerror(errno));
816 816 return (-1);
817 817 }
818 818
819 819 lock.l_type = F_WRLCK;
820 820 lock.l_whence = SEEK_SET;
821 821 lock.l_start = 0;
822 822 lock.l_len = 0;
823 823
824 824 retry:
825 825 if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
826 826 if (errno == EAGAIN || errno == EINTR)
827 827 goto retry;
828 828 (void) close(lock_fd);
829 829 syslog(LOG_ERR, MSG_LOCK_SET_ERR,
830 830 whoami, lock_file, strerror(errno));
831 831 return (-1);
832 832 }
833 833
834 834 return (lock_fd);
835 835 }
836 836
837 837
838 838 static void
839 839 exit_lock(int lock_fd, char *lock_file)
840 840 {
841 841 struct flock lock;
842 842
843 843 lock.l_type = F_UNLCK;
844 844 lock.l_whence = SEEK_SET;
845 845 lock.l_start = 0;
846 846 lock.l_len = 0;
847 847
848 848 if (fcntl(lock_fd, F_SETLK, &lock) == -1) {
849 849 syslog(LOG_ERR, MSG_LOCK_CLR_ERR,
850 850 whoami, lock_file, strerror(errno));
851 851 }
852 852
853 853 if (close(lock_fd) == -1) {
854 854 syslog(LOG_ERR, MSG_LOCK_CLOSE_ERR,
855 855 whoami, lock_file, strerror(errno));
856 856 }
857 857 }
858 858
859 859
860 860 /*
861 861 * Free the events specification table, constructed by
862 862 * parsing all the sysevent.conf files found.
863 863 *
864 864 * The free of this table is in response to a HUP
865 865 * given to the syseventd daemon, permitting the
866 866 * table to be rebuilt after adding a new sysevent.conf
867 867 * file or changing an existing one without shutting
868 868 * down the daemon.
869 869 */
870 870 static void
871 871 free_event_table()
872 872 {
873 873 syseventtab_t *sep;
874 874 syseventtab_t *sep_next;
875 875 conftab_t *cfp;
876 876 conftab_t *cfp_next;
877 877
878 878 sep = syseventtab;
879 879 while (sep) {
880 880 sc_strfree(sep->se_vendor);
881 881 sc_strfree(sep->se_publisher);
882 882 sc_strfree(sep->se_class);
883 883 sc_strfree(sep->se_subclass);
884 884 sc_strfree(sep->se_user);
885 885 sc_strfree(sep->se_reserved1);
886 886 sc_strfree(sep->se_reserved2);
887 887 sc_strfree(sep->se_path);
888 888 if (sep->se_args)
889 889 sc_strfree(sep->se_args);
890 890 sep_next = sep->se_next;
891 891 sc_free(sep, sizeof (syseventtab_t));
892 892 sep = sep_next;
893 893 }
894 894 syseventtab = NULL;
895 895
896 896 cfp = conftab;
897 897 while (cfp) {
898 898 sc_strfree(cfp->cf_conf_file);
899 899 cfp_next = cfp->cf_next;
900 900 sc_free(cfp, sizeof (conftab_t));
901 901 cfp = cfp_next;
902 902 }
903 903 conftab = NULL;
904 904 }
905 905
906 906
907 907
908 908 static char ident_chars[] = "_";
909 909
910 910 /*
911 911 * Return a dynamically-allocated string containing the
912 912 * the next identifier in the string being parsed, pointed
913 913 * at by 'id'. 'end' returns a pointer to the character
914 914 * after the identifier.
915 915 *
916 916 * Identifiers are all alphanumeric ascii characters and
917 917 * those contained in ident_chars.
918 918 *
919 919 * The returned string must be explicitly freed via
920 920 * freestr().
921 921 */
922 922 static str_t *
923 923 snip_identifier(char *id, char **end)
924 924 {
925 925 str_t *token;
926 926
927 927 if ((token = initstr(32)) == NULL)
928 928 return (NULL);
929 929
930 930 while (*id != 0) {
931 931 if (isascii(*id) &&
932 932 (isalnum(*id) || strchr(ident_chars, *id) != NULL)) {
933 933 if (strcatc(token, *id++)) {
934 934 freestr(token);
935 935 return (NULL);
936 936 }
937 937 } else {
938 938 *end = id;
939 939 return (token);
940 940 }
941 941 }
942 942
943 943 *end = id;
944 944 return (token);
945 945 }
946 946
947 947
948 948 /*
949 949 * Identical to snip_identifier(), but the identifier
950 950 * is delimited by the characters { and }.
951 951 */
952 952 static str_t *
953 953 snip_delimited_identifier(char *id, char **end)
954 954 {
955 955 str_t *token;
956 956
957 957 if ((token = initstr(32)) == NULL)
958 958 return (NULL);
959 959
960 960 while (*id != 0) {
961 961 if (*id == '}') {
962 962 *end = id+1;
963 963 return (token);
964 964 }
965 965 if (strcatc(token, *id++)) {
966 966 freestr(token);
967 967 return (NULL);
968 968 }
969 969 }
970 970
971 971 if (*id == 0) {
972 972 freestr(token);
973 973 return (NULL);
974 974 }
975 975
976 976 *end = id;
977 977 return (token);
978 978 }
979 979
980 980
981 981 /*
982 982 * Return a string with the name of the attribute type
983 983 */
984 984 static char *nv_attr_type_strings[] = {
985 985 "unknown",
986 986 "boolean",
987 987 "byte",
988 988 "int16",
989 989 "uint16",
990 990 "int32",
991 991 "uint32",
992 992 "int64",
993 993 "uint64",
994 994 "string",
995 995 "byte-array",
996 996 "int16-array",
997 997 "uint16-array",
998 998 "int32-array",
999 999 "uint32-array",
1000 1000 "int64-array",
1001 1001 "uint64-array",
1002 1002 "string-array",
1003 1003 "hrtime"
1004 1004 };
1005 1005
1006 1006 static char *
1007 1007 se_attr_type_to_str(int se_attr_type)
1008 1008 {
1009 1009 if (se_attr_type >= 0 &&
1010 1010 se_attr_type < sizeof (nv_attr_type_strings) / sizeof (char *)) {
1011 1011 return (nv_attr_type_strings[se_attr_type]);
1012 1012 }
1013 1013 return (nv_attr_type_strings[DATA_TYPE_UNKNOWN]);
1014 1014 }
1015 1015
1016 1016
1017 1017 /*
1018 1018 * Find and return the data matching the macro name 'token'
1019 1019 *
1020 1020 * Predefined macros are simply substituted with the
1021 1021 * data from the event header:
1022 1022 *
1023 1023 * $vendor - the vendor string defining the event.
1024 1024 *
1025 1025 * $publisher - the publisher string defining the event.
1026 1026 *
1027 1027 * $class - the class string defining the event.
1028 1028 *
1029 1029 * $subclass - the subclass string defining the event.
1030 1030 *
1031 1031 * $sequence - the sequence number of the event.
1032 1032 *
1033 1033 * $timestamp - the timestamp of the event.
1034 1034 *
1035 1035 * Attributes with signed data types (DATA_TYPE_INT16,
1036 1036 * DATA_TYPE_INT32 and DATA_TYPE_INT64) are expanded
1037 1037 * as decimal digits.
1038 1038 *
1039 1039 * Attributes with unsigned data types (DATA_TYPE_BYTE,
1040 1040 * DATA_TYPE_UINT16, DATA_TYPE_UINT32, DATA_TYPE_UINT64 and
1041 1041 * DATA_TYPE_HTTIME) are expanded as hexadecimal digits
1042 1042 * with a "0x" prefix.
1043 1043 *
1044 1044 * Attributes with string data type (DATA_TYPE_STRING)
1045 1045 * are expanded with the string data. The data is
1046 1046 * not quoted. If if it desired that the quoted strings
1047 1047 * be generated on the command line, put quotes around
1048 1048 * the macro call in the arguments.
1049 1049 *
1050 1050 * Array types are expanded with each element expanded
1051 1051 * as defined for that scalar type, with a space separating
1052 1052 * each element substitution.
1053 1053 */
1054 1054
1055 1055 static str_t *
1056 1056 find_macro_definition(sysevent_t *ev, nvlist_t *nvlist, syseventtab_t *sep,
1057 1057 char *token, sysevent_hdr_info_t *hdr)
1058 1058 {
1059 1059 nvpair_t *nvp;
1060 1060 int nmatches;
1061 1061 char num[64];
1062 1062 str_t *replacement;
1063 1063 int i;
1064 1064 uint_t nelems;
1065 1065 union {
1066 1066 uchar_t x_byte;
1067 1067 int16_t x_int16;
1068 1068 uint16_t x_uint16;
1069 1069 int32_t x_int32;
1070 1070 uint32_t x_uint32;
1071 1071 int64_t x_int64;
1072 1072 uint64_t x_uint64;
1073 1073 hrtime_t x_time;
1074 1074 char *x_string;
1075 1075 uchar_t *x_byte_array;
1076 1076 int16_t *x_int16_array;
1077 1077 int32_t *x_int32_array;
1078 1078 int64_t *x_int64_array;
1079 1079 uint16_t *x_uint16_array;
1080 1080 uint32_t *x_uint32_array;
1081 1081 uint64_t *x_uint64_array;
1082 1082 char **x_string_array;
1083 1083 } x;
1084 1084
1085 1085
1086 1086 if ((replacement = initstr(128)) == NULL) {
1087 1087 return (NULL);
1088 1088 }
1089 1089
1090 1090 if (strcmp(token, "vendor") == 0) {
1091 1091 if (strcopys(replacement, hdr->vendor)) {
1092 1092 freestr(replacement);
1093 1093 return (NULL);
1094 1094 }
1095 1095 return (replacement);
1096 1096 }
1097 1097
1098 1098 if (strcmp(token, "publisher") == 0) {
1099 1099 if (strcopys(replacement, hdr->publisher)) {
1100 1100 freestr(replacement);
1101 1101 return (NULL);
1102 1102 }
1103 1103 return (replacement);
1104 1104 }
1105 1105
1106 1106 if (strcmp(token, "class") == 0) {
1107 1107 if (strcopys(replacement, hdr->class)) {
1108 1108 freestr(replacement);
1109 1109 return (NULL);
1110 1110 }
1111 1111 return (replacement);
1112 1112 }
1113 1113
1114 1114 if (strcmp(token, "subclass") == 0) {
1115 1115 if (strcopys(replacement, hdr->subclass)) {
1116 1116 freestr(replacement);
1117 1117 return (NULL);
1118 1118 }
1119 1119 return (replacement);
1120 1120 }
1121 1121
1122 1122 if ((strcmp(token, "sequence") == 0) ||
1123 1123 (strcmp(token, "timestamp") == 0)) {
1124 1124 if (strcmp(token, "sequence") == 0) {
1125 1125 (void) snprintf(num, sizeof (num),
1126 1126 "0x%llx", sysevent_get_seq(ev));
1127 1127 } else {
1128 1128 hrtime_t ts;
1129 1129 sysevent_get_time(ev, &ts);
1130 1130 (void) snprintf(num, sizeof (num), "0x%llx", ts);
1131 1131 }
1132 1132 if (strcopys(replacement, num)) {
1133 1133 freestr(replacement);
1134 1134 return (NULL);
1135 1135 }
1136 1136 return (replacement);
1137 1137 }
1138 1138
1139 1139 nmatches = 0;
1140 1140
1141 1141 if (nvlist) {
1142 1142 nvpair_t *nvp_match;
1143 1143 nvp = NULL;
1144 1144 while ((nvp = nvlist_next_nvpair(nvlist, nvp)) != NULL) {
1145 1145 if (debug_level >= DBG_DETAILED) {
1146 1146 syseventd_print(DBG_DETAILED,
1147 1147 " attribute: %s %s\n", nvpair_name(nvp),
1148 1148 se_attr_type_to_str(nvpair_type(nvp)));
1149 1149 }
1150 1150 if (strcmp(token, nvpair_name(nvp)) == 0) {
1151 1151 nmatches++;
1152 1152 nvp_match = nvp;
1153 1153 }
1154 1154 }
1155 1155 nvp = nvp_match;
1156 1156 }
1157 1157
1158 1158 if (nmatches == 0) {
1159 1159 syslog(LOG_ERR, MACRO_UNDEF_ERR,
1160 1160 sep->se_conf_file, sep->se_lineno, token);
1161 1161 freestr(replacement);
1162 1162 return (NULL);
1163 1163 } else if (nmatches > 1) {
1164 1164 syslog(LOG_ERR, MACRO_MULT_DEF_ERR,
1165 1165 sep->se_conf_file, sep->se_lineno, token);
1166 1166 freestr(replacement);
1167 1167 return (NULL);
1168 1168 }
1169 1169
1170 1170 switch (nvpair_type(nvp)) {
1171 1171 case DATA_TYPE_BYTE:
1172 1172 (void) nvpair_value_byte(nvp, &x.x_byte);
1173 1173 (void) snprintf(num, sizeof (num), "0x%x", x.x_byte);
1174 1174 if (strcats(replacement, num)) {
1175 1175 freestr(replacement);
1176 1176 return (NULL);
1177 1177 }
1178 1178 break;
1179 1179 case DATA_TYPE_INT16:
1180 1180 (void) nvpair_value_int16(nvp, &x.x_int16);
1181 1181 (void) snprintf(num, sizeof (num), "%d", x.x_int16);
1182 1182 if (strcats(replacement, num)) {
1183 1183 freestr(replacement);
1184 1184 return (NULL);
1185 1185 }
1186 1186 break;
1187 1187 case DATA_TYPE_UINT16:
1188 1188 (void) nvpair_value_uint16(nvp, &x.x_uint16);
1189 1189 (void) snprintf(num, sizeof (num), "0x%x", x.x_uint16);
1190 1190 if (strcats(replacement, num)) {
1191 1191 freestr(replacement);
1192 1192 return (NULL);
1193 1193 }
1194 1194 break;
1195 1195 case DATA_TYPE_INT32:
1196 1196 (void) nvpair_value_int32(nvp, &x.x_int32);
1197 1197 (void) snprintf(num, sizeof (num), "%d", x.x_int32);
1198 1198 if (strcats(replacement, num)) {
1199 1199 freestr(replacement);
1200 1200 return (NULL);
1201 1201 }
1202 1202 break;
1203 1203 case DATA_TYPE_UINT32:
1204 1204 (void) nvpair_value_uint32(nvp, &x.x_uint32);
1205 1205 (void) snprintf(num, sizeof (num), "0x%x", x.x_uint32);
1206 1206 if (strcats(replacement, num)) {
1207 1207 freestr(replacement);
1208 1208 return (NULL);
1209 1209 }
1210 1210 break;
1211 1211 case DATA_TYPE_INT64:
1212 1212 (void) nvpair_value_int64(nvp, &x.x_int64);
1213 1213 (void) snprintf(num, sizeof (num), "%lld", x.x_int64);
1214 1214 if (strcats(replacement, num)) {
1215 1215 freestr(replacement);
1216 1216 return (NULL);
1217 1217 }
1218 1218 break;
1219 1219 case DATA_TYPE_UINT64:
1220 1220 (void) nvpair_value_uint64(nvp, &x.x_uint64);
1221 1221 (void) snprintf(num, sizeof (num), "0x%llx", x.x_uint64);
1222 1222 if (strcats(replacement, num)) {
1223 1223 freestr(replacement);
1224 1224 return (NULL);
1225 1225 }
1226 1226 break;
1227 1227 case DATA_TYPE_STRING:
1228 1228 (void) nvpair_value_string(nvp, &x.x_string);
1229 1229 if (strcats(replacement, x.x_string)) {
1230 1230 freestr(replacement);
1231 1231 return (NULL);
1232 1232 }
1233 1233 break;
1234 1234 case DATA_TYPE_BYTE_ARRAY: {
1235 1235 uchar_t *p;
1236 1236 (void) nvpair_value_byte_array(nvp,
1237 1237 &x.x_byte_array, &nelems);
1238 1238 p = x.x_byte_array;
1239 1239 for (i = 0; i < nelems; i++) {
1240 1240 (void) snprintf(num, sizeof (num),
1241 1241 "0x%x ", *p++ & 0xff);
1242 1242 if (strcats(replacement, num)) {
1243 1243 freestr(replacement);
1244 1244 return (NULL);
1245 1245 }
1246 1246 }
1247 1247 }
1248 1248 break;
1249 1249 case DATA_TYPE_INT16_ARRAY: {
1250 1250 int16_t *p;
1251 1251 (void) nvpair_value_int16_array(nvp,
1252 1252 &x.x_int16_array, &nelems);
1253 1253 p = x.x_int16_array;
1254 1254 for (i = 0; i < nelems; i++) {
1255 1255 (void) snprintf(num, sizeof (num), "%d ", *p++);
1256 1256 if (strcats(replacement, num)) {
1257 1257 freestr(replacement);
1258 1258 return (NULL);
1259 1259 }
1260 1260 }
1261 1261 }
1262 1262 break;
1263 1263
1264 1264 case DATA_TYPE_UINT16_ARRAY: {
1265 1265 uint16_t *p;
1266 1266 (void) nvpair_value_uint16_array(nvp,
1267 1267 &x.x_uint16_array, &nelems);
1268 1268 p = x.x_uint16_array;
1269 1269 for (i = 0; i < nelems; i++) {
1270 1270 (void) snprintf(num, sizeof (num),
1271 1271 "0x%x ", *p++);
1272 1272 if (strcats(replacement, num)) {
1273 1273 freestr(replacement);
1274 1274 return (NULL);
1275 1275 }
1276 1276 }
1277 1277 }
1278 1278 break;
1279 1279
1280 1280 case DATA_TYPE_INT32_ARRAY: {
1281 1281 int32_t *p;
1282 1282 (void) nvpair_value_int32_array(nvp,
1283 1283 &x.x_int32_array, &nelems);
1284 1284 p = x.x_int32_array;
1285 1285 for (i = 0; i < nelems; i++) {
1286 1286 (void) snprintf(num, sizeof (num), "%d ", *p++);
1287 1287 if (strcats(replacement, num)) {
1288 1288 freestr(replacement);
1289 1289 return (NULL);
1290 1290 }
1291 1291 }
1292 1292 }
1293 1293 break;
1294 1294
1295 1295 case DATA_TYPE_UINT32_ARRAY: {
1296 1296 uint32_t *p;
1297 1297 (void) nvpair_value_uint32_array(nvp,
1298 1298 &x.x_uint32_array, &nelems);
1299 1299 p = x.x_uint32_array;
1300 1300 for (i = 0; i < nelems; i++) {
1301 1301 (void) snprintf(num, sizeof (num),
1302 1302 "0x%x ", *p++);
1303 1303 if (strcats(replacement, num)) {
1304 1304 freestr(replacement);
1305 1305 return (NULL);
1306 1306 }
1307 1307 }
1308 1308 }
1309 1309 break;
1310 1310
1311 1311 case DATA_TYPE_INT64_ARRAY: {
1312 1312 int64_t *p;
1313 1313 (void) nvpair_value_int64_array(nvp,
1314 1314 &x.x_int64_array, &nelems);
1315 1315 p = x.x_int64_array;
1316 1316 for (i = 0; i < nelems; i++) {
1317 1317 (void) snprintf(num, sizeof (num),
1318 1318 "%lld ", *p++);
1319 1319 if (strcats(replacement, num)) {
1320 1320 freestr(replacement);
1321 1321 return (NULL);
1322 1322 }
1323 1323 }
1324 1324 }
1325 1325 break;
1326 1326
1327 1327 case DATA_TYPE_UINT64_ARRAY: {
1328 1328 uint64_t *p;
1329 1329 (void) nvpair_value_uint64_array(nvp,
1330 1330 &x.x_uint64_array, &nelems);
1331 1331 p = x.x_uint64_array;
1332 1332 for (i = 0; i < nelems; i++) {
1333 1333 (void) snprintf(num, sizeof (num),
1334 1334 "0x%llx ", *p++);
1335 1335 if (strcats(replacement, num)) {
1336 1336 freestr(replacement);
1337 1337 return (NULL);
1338 1338 }
1339 1339 }
1340 1340 }
1341 1341 break;
1342 1342
1343 1343 case DATA_TYPE_STRING_ARRAY: {
1344 1344 char **p;
1345 1345 (void) nvpair_value_string_array(nvp,
1346 1346 &x.x_string_array, &nelems);
1347 1347 p = x.x_string_array;
1348 1348 for (i = 0; i < nelems; i++) {
1349 1349 if (strcats(replacement, *p++) ||
1350 1350 strcats(replacement, " ")) {
1351 1351 freestr(replacement);
1352 1352 return (NULL);
1353 1353 }
1354 1354 }
1355 1355 }
1356 1356 break;
1357 1357
1358 1358 case DATA_TYPE_HRTIME:
1359 1359 (void) nvpair_value_hrtime(nvp, &x.x_time);
1360 1360 (void) snprintf(num, sizeof (num), "0x%llx", x.x_time);
1361 1361 if (strcats(replacement, num)) {
1362 1362 freestr(replacement);
1363 1363 return (NULL);
1364 1364 }
1365 1365 break;
1366 1366 default:
1367 1367 syslog(LOG_ERR, ATTR_UNSUPPORTED_ERR,
1368 1368 sep->se_conf_file, sep->se_lineno,
1369 1369 nvpair_type(nvp), token);
1370 1370 freestr(replacement);
1371 1371 return (NULL);
1372 1372 }
1373 1373
1374 1374 return (replacement);
1375 1375 }
1376 1376
1377 1377 /*
1378 1378 * Expand macros in the command template provided in an event
1379 1379 * specification with the data from the event or event attributes.
1380 1380 *
1381 1381 * Macros are introduced by the '$' character, with the macro
1382 1382 * name being the following token separated by a SPACE or
1383 1383 * TAB character. If the macro name is embedded in text,
1384 1384 * it may be delineated by '${' and "}'. A backslash before
1385 1385 * the '$' causes macro expansion not to occur.
1386 1386 *
1387 1387 * The following predefined macros are defined for each event:
1388 1388 *
1389 1389 * $vendor - the vendor string defining the event.
1390 1390 *
1391 1391 * $publisher - the publisher string defining the event.
1392 1392 *
1393 1393 * $class - the class string defining the event.
1394 1394 *
1395 1395 * $subclass - the subclass string defining the event.
1396 1396 *
1397 1397 * $sequence - the sequence number of the event.
1398 1398 *
1399 1399 * $timestamp - the timestamp of the event.
1400 1400 *
1401 1401 *
1402 1402 * Macro names other than those predefined are compared against
1403 1403 * the attribute list provided with the event. An attribute
1404 1404 * with name matching the macro name causes the value of
1405 1405 * of the attribute to be substituted as ASCII text on the
1406 1406 * generated command line.
1407 1407 *
1408 1408 * Use of a macro for which no attribute with that name
1409 1409 * is defined, or for which multiple attributes with that
1410 1410 * name are provided, cause an error and the command is
1411 1411 * not invoked.
1412 1412 */
1413 1413 static int
1414 1414 expand_macros(sysevent_t *ev, nvlist_t *nvlist, syseventtab_t *sep,
1415 1415 str_t *line, sysevent_hdr_info_t *hdr)
1416 1416 {
1417 1417 char *p;
1418 1418 int state;
1419 1419 char *end;
1420 1420 str_t *token;
1421 1421 str_t *remainder;
1422 1422 str_t *replacement;
1423 1423 int count;
1424 1424 int dollar_position;
1425 1425
1426 1426 syseventd_print(DBG_MACRO, " expanding macros: '%s'\n", line->s_str);
1427 1427
1428 1428 reset:
1429 1429 state = 0;
1430 1430 count = 0;
1431 1431 for (p = line->s_str; *p != 0; p++, count++) {
1432 1432 switch (state) {
1433 1433 case 0: /* initial state */
1434 1434 if (*p == '\\') {
1435 1435 state = 1;
1436 1436 } else if (*p == '$') {
1437 1437 dollar_position = count;
1438 1438 state = 2;
1439 1439 }
1440 1440 break;
1441 1441 case 1: /* skip characters */
1442 1442 state = 0; /* after backslash */
1443 1443 break;
1444 1444 case 2: /* character after $ */
1445 1445 if (*p == '{') {
1446 1446 token = snip_delimited_identifier(p+1, &end);
1447 1447 } else {
1448 1448 token = snip_identifier(p, &end);
1449 1449 }
1450 1450 if (token == NULL)
1451 1451 goto failed;
1452 1452
1453 1453 if ((remainder = initstr(128)) == NULL) {
1454 1454 freestr(token);
1455 1455 return (1);
1456 1456 }
1457 1457 if (strcopys(remainder, end)) {
1458 1458 freestr(token);
1459 1459 freestr(remainder);
1460 1460 return (1);
1461 1461 }
1462 1462 replacement = find_macro_definition(ev, nvlist,
1463 1463 sep, token->s_str, hdr);
1464 1464 if (replacement == NULL) {
1465 1465 freestr(token);
1466 1466 freestr(remainder);
1467 1467 return (1);
1468 1468 }
1469 1469 syseventd_print(DBG_MACRO,
1470 1470 " '%s' expands to '%s'\n",
1471 1471 token->s_str, replacement->s_str);
1472 1472
1473 1473 strtrunc(line, dollar_position);
1474 1474 if (strcats(line, replacement->s_str)) {
1475 1475 freestr(token);
1476 1476 freestr(replacement);
1477 1477 freestr(remainder);
1478 1478 return (1);
1479 1479 }
1480 1480 if (strcats(line, remainder->s_str)) {
1481 1481 freestr(token);
1482 1482 freestr(replacement);
1483 1483 freestr(remainder);
1484 1484 return (1);
1485 1485 }
1486 1486
1487 1487 syseventd_print(DBG_MACRO,
1488 1488 " with macro expanded: '%s'\n", line->s_str);
1489 1489
1490 1490 freestr(token);
1491 1491 freestr(replacement);
1492 1492 freestr(remainder);
1493 1493 goto reset;
1494 1494 }
1495 1495 }
1496 1496
1497 1497 failed:
1498 1498 if (state != 0) {
1499 1499 syslog(LOG_ERR, SYNTAX_ERR, sep->se_conf_file, sep->se_lineno);
1500 1500 return (1);
1501 1501 }
1502 1502
1503 1503 return (0);
1504 1504 }
1505 1505
1506 1506
1507 1507 static void
1508 1508 start_syseventconfd()
1509 1509 {
1510 1510 int err;
1511 1511
1512 1512 err = system1("/usr/lib/sysevent/syseventconfd",
1513 1513 "/usr/lib/sysevent/syseventconfd");
1514 1514
1515 1515 if (err != 0 && confd_err_msg_emitted == 0) {
1516 1516 if (confd_state == CONFD_STATE_NOT_RUNNING) {
1517 1517 syslog(LOG_ERR, SYSEVENTCONFD_START_ERR,
1518 1518 strerror(errno));
1519 1519 } else {
1520 1520 syslog(LOG_ERR, SYSEVENTCONFD_RESTART_ERR,
1521 1521 strerror(errno));
1522 1522 }
1523 1523 }
1524 1524 }
1525 1525
1526 1526
1527 1527 static int
1528 1528 system1(const char *s_path, const char *s)
1529 1529 {
1530 1530 struct sigaction cbuf, ibuf, qbuf, ignore, dfl;
1531 1531 sigset_t mask;
1532 1532 sigset_t savemask;
1533 1533 struct stat st;
1534 1534 pid_t pid;
1535 1535 int status, w;
1536 1536
1537 1537 /* Check the requested command */
1538 1538 if (s == NULL) {
1539 1539 errno = EINVAL;
1540 1540 return (-1);
1541 1541 }
1542 1542
1543 1543 /* Check the ability to execute devfsadmd from this process */
1544 1544 if (stat(s_path, &st) < 0) {
1545 1545 return (-1);
1546 1546 }
1547 1547 if (((geteuid() == st.st_uid) && ((st.st_mode & S_IXUSR) == 0)) ||
1548 1548 ((getegid() == st.st_gid) && ((st.st_mode & S_IXGRP) == 0)) ||
1549 1549 ((st.st_mode & S_IXOTH) == 0)) {
1550 1550 errno = EPERM;
1551 1551 return (-1);
1552 1552 }
1553 1553
1554 1554 /*
1555 1555 * Block SIGCHLD and set up a default handler for the duration of the
1556 1556 * system1 call.
1557 1557 */
1558 1558 (void) sigemptyset(&mask);
1559 1559 (void) sigaddset(&mask, SIGCHLD);
1560 1560 (void) sigprocmask(SIG_BLOCK, &mask, &savemask);
1561 1561 (void) memset(&dfl, 0, sizeof (dfl));
1562 1562 dfl.sa_handler = SIG_DFL;
1563 1563 (void) sigaction(SIGCHLD, &dfl, &cbuf);
1564 1564
1565 1565 /* Fork off the child process (using fork1(), because it's MT-safe) */
1566 1566 switch (pid = fork1()) {
1567 1567 case -1:
1568 1568 /* Error */
1569 1569 (void) sigaction(SIGCHLD, &cbuf, NULL);
1570 1570 (void) sigprocmask(SIG_SETMASK, &savemask, NULL);
1571 1571 return (-1);
1572 1572 case 0:
1573 1573 /* Set-up an initial signal mask for the child */
1574 1574 (void) sigemptyset(&mask);
1575 1575 (void) sigprocmask(SIG_SETMASK, &mask, NULL);
1576 1576 closefrom(3);
1577 1577 (void) execl(s_path, s, (char *)0);
1578 1578 _exit(-1);
1579 1579 break;
1580 1580 default:
1581 1581 /* Parent */
1582 1582 break;
1583 1583 }
1584 1584
1585 1585 (void) memset(&ignore, 0, sizeof (ignore));
1586 1586 ignore.sa_handler = SIG_IGN;
1587 1587 (void) sigaction(SIGINT, &ignore, &ibuf);
1588 1588 (void) sigaction(SIGQUIT, &ignore, &qbuf);
1589 1589
1590 1590 do {
1591 1591 w = waitpid(pid, &status, 0);
1592 1592 } while (w == -1 && errno == EINTR);
1593 1593
1594 1594 (void) sigaction(SIGINT, &ibuf, NULL);
1595 1595 (void) sigaction(SIGQUIT, &qbuf, NULL);
1596 1596
1597 1597 (void) sigaction(SIGCHLD, &cbuf, NULL);
1598 1598 (void) sigprocmask(SIG_SETMASK, &savemask, NULL);
1599 1599
1600 1600 return ((w == -1)? w: status);
1601 1601 }
1602 1602
1603 1603 /*
1604 1604 * Free all commands on the cmd queue
1605 1605 */
1606 1606 static void
1607 1607 abort_cmd_queue()
1608 1608 {
1609 1609 cmdqueue_t *cmd;
1610 1610 cmdqueue_t *next;
1611 1611 int nevents = 0;
1612 1612
1613 1613 while ((cmd = cmdq) != NULL) {
1614 1614 next = cmd->next;
1615 1615 cmdq_cnt--;
1616 1616 sysevent_free(cmd->event);
1617 1617 sc_free(cmd, sizeof (cmdqueue_t));
1618 1618 cmdq = next;
1619 1619 nevents++;
1620 1620 }
1621 1621 cmdq_tail = NULL;
1622 1622
1623 1623 /*
1624 1624 * Generate error msgs if events were discarded or
1625 1625 * we are entering the disabled state.
1626 1626 */
1627 1627 if (nevents > 0) {
1628 1628 syslog(LOG_ERR, N_EVENTS_DISCARDED_ERR, nevents);
1629 1629 }
1630 1630 if (want_fini == 0) {
1631 1631 confd_state = CONFD_STATE_DISABLED;
1632 1632 syslog(LOG_ERR, SERVICE_DISABLED_MSG);
1633 1633 }
1634 1634 }
1635 1635
1636 1636 /*
1637 1637 * For a matching event specification, build the command to be
1638 1638 * invoked in response to the event. Building the command involves
1639 1639 * expanding macros supplied in the event specification command
1640 1640 * with values from the actual event. These macros can be
1641 1641 * the class/subclass/vendor/publisher strings, or arbitrary
1642 1642 * attribute data attached to the event.
1643 1643 *
1644 1644 * This module does not invoke (fork/exec) the command itself,
1645 1645 * since this module is running in the context of the syseventd
1646 1646 * daemon, and fork/exec's done here interfere with the door
1647 1647 * upcall delivering events from the kernel to the daemon.
1648 1648 * Instead, we build a separate event and nvlist with the
1649 1649 * attributes of the command to be invoked, and pass that on
1650 1650 * to the syseventconfd daemon, which is basically a fork/exec
1651 1651 * server on our behalf.
1652 1652 *
1653 1653 * Errors queuing the event are returned to syseventd with
1654 1654 * EAGAIN, allowing syseventd to manage a limited number of
1655 1655 * retries after a short delay.
1656 1656 */
1657 1657 static int
1658 1658 queue_event(sysevent_t *ev, syseventtab_t *sep, sysevent_hdr_info_t *hdr)
1659 1659 {
1660 1660 str_t *line;
1661 1661 nvlist_t *nvlist;
1662 1662 char *argv0;
1663 1663 sysevent_t *cmd_event;
1664 1664 nvlist_t *cmd_nvlist;
1665 1665 cmdqueue_t *new_cmd;
1666 1666
1667 1667 if ((line = initstr(128)) == NULL)
1668 1668 return (1);
1669 1669
1670 1670 if ((argv0 = strrchr(sep->se_path, '/')) == NULL) {
1671 1671 argv0 = sep->se_path;
1672 1672 } else {
1673 1673 argv0++;
1674 1674 }
1675 1675 if (strcopys(line, argv0)) {
1676 1676 freestr(line);
1677 1677 return (1);
1678 1678 }
1679 1679
1680 1680 if (sep->se_args) {
1681 1681 if (strcats(line, " ")) {
1682 1682 freestr(line);
1683 1683 return (1);
1684 1684 }
1685 1685 if (strcats(line, sep->se_args)) {
1686 1686 freestr(line);
1687 1687 return (1);
1688 1688 }
↓ open down ↓ |
1688 lines elided |
↑ open up ↑ |
1689 1689
1690 1690 if (sysevent_get_attr_list(ev, &nvlist) != 0) {
1691 1691 syslog(LOG_ERR, GET_ATTR_LIST_ERR,
1692 1692 sep->se_conf_file, sep->se_lineno,
1693 1693 strerror(errno));
1694 1694 freestr(line);
1695 1695 return (1);
1696 1696 }
1697 1697 if (expand_macros(ev, nvlist, sep, line, hdr)) {
1698 1698 freestr(line);
1699 - if (nvlist)
1700 - nvlist_free(nvlist);
1699 + nvlist_free(nvlist);
1701 1700 return (1);
1702 1701 }
1703 - if (nvlist)
1704 - nvlist_free(nvlist);
1702 + nvlist_free(nvlist);
1705 1703 }
1706 1704
1707 1705 if (debug_level >= DBG_EXEC) {
1708 1706 syseventd_print(DBG_EXEC, "%s, line %d: path = %s\n",
1709 1707 sep->se_conf_file, sep->se_lineno, sep->se_path);
1710 1708 syseventd_print(DBG_EXEC, " cmd = %s\n", line->s_str);
1711 1709 }
1712 1710
1713 1711 cmd_nvlist = NULL;
1714 1712 if ((errno = nvlist_alloc(&cmd_nvlist, NV_UNIQUE_NAME, 0)) != 0) {
1715 1713 freestr(line);
1716 1714 syslog(LOG_ERR, NVLIST_ALLOC_ERR,
1717 1715 sep->se_conf_file, sep->se_lineno,
1718 1716 strerror(errno));
1719 1717 return (1);
1720 1718 }
1721 1719
1722 1720 if ((errno = nvlist_add_string(cmd_nvlist, "path", sep->se_path)) != 0)
1723 1721 goto err;
1724 1722 if ((errno = nvlist_add_string(cmd_nvlist, "cmd", line->s_str)) != 0)
1725 1723 goto err;
1726 1724 if ((errno = nvlist_add_string(cmd_nvlist, "file",
1727 1725 sep->se_conf_file)) != 0)
1728 1726 goto err;
1729 1727 if ((errno = nvlist_add_int32(cmd_nvlist, "line", sep->se_lineno)) != 0)
1730 1728 goto err;
1731 1729 if ((errno = nvlist_add_string(cmd_nvlist, "user", sep->se_user)) != 0)
1732 1730 goto err;
1733 1731
1734 1732 if (sep->se_uid != (uid_t)0) {
1735 1733 if ((errno = nvlist_add_int32(cmd_nvlist, "uid",
1736 1734 sep->se_uid)) != 0)
1737 1735 goto err;
1738 1736 if ((errno = nvlist_add_int32(cmd_nvlist, "gid",
1739 1737 sep->se_gid)) != 0)
1740 1738 goto err;
1741 1739 }
1742 1740
1743 1741 cmd_event = sysevent_alloc_event(hdr->class, hdr->subclass, hdr->vendor,
1744 1742 hdr->publisher, cmd_nvlist);
1745 1743 if (cmd_event == NULL) {
1746 1744 syslog(LOG_ERR, SYSEVENT_ALLOC_ERR,
1747 1745 sep->se_conf_file, sep->se_lineno,
1748 1746 strerror(errno));
1749 1747 nvlist_free(cmd_nvlist);
1750 1748 freestr(line);
1751 1749 return (1);
1752 1750 }
1753 1751
1754 1752 nvlist_free(cmd_nvlist);
1755 1753 freestr(line);
1756 1754
1757 1755 /*
1758 1756 * Place cmd_event on queue to be transported to syseventconfd
1759 1757 */
1760 1758 if ((new_cmd = sc_malloc(sizeof (cmdqueue_t))) == NULL) {
1761 1759 sysevent_free(cmd_event);
1762 1760 return (1);
1763 1761 }
1764 1762 new_cmd->event = cmd_event;
1765 1763 new_cmd->next = NULL;
1766 1764 (void) mutex_lock(&cmdq_lock);
1767 1765 if (cmdq == NULL) {
1768 1766 cmdq = new_cmd;
1769 1767 } else {
1770 1768 cmdq_tail->next = new_cmd;
1771 1769 }
1772 1770 cmdq_cnt++;
1773 1771 cmdq_tail = new_cmd;
1774 1772
1775 1773 /*
1776 1774 * signal queue flush thread
1777 1775 */
1778 1776 (void) cond_signal(&cmdq_cv);
1779 1777
1780 1778 (void) mutex_unlock(&cmdq_lock);
1781 1779
1782 1780 return (0);
1783 1781
1784 1782 err:
1785 1783 syslog(LOG_ERR, NVLIST_BUILD_ERR,
1786 1784 sep->se_conf_file, sep->se_lineno, strerror(errno));
1787 1785 nvlist_free(cmd_nvlist);
1788 1786 freestr(line);
1789 1787 return (1);
1790 1788 }
1791 1789
1792 1790
1793 1791 static int
1794 1792 transport_event(sysevent_t *event)
1795 1793 {
1796 1794 int rval;
1797 1795
1798 1796 rval = sysevent_send_event(confd_handle, event);
1799 1797 if (rval != 0) {
1800 1798 switch (errno) {
1801 1799 case EAGAIN:
1802 1800 case EINTR:
1803 1801 /*
1804 1802 * syseventconfd daemon may be forking, stop
1805 1803 * attempting to empty the queue momentarily.
1806 1804 */
1807 1805 rval = errno;
1808 1806 break;
1809 1807 case ENOENT:
1810 1808 case EBADF:
1811 1809 /*
1812 1810 * start/restart the syseventconfd daemon,
1813 1811 * allowing for some delay when starting
1814 1812 * up before it begins to reply.
1815 1813 */
1816 1814 if (confd_state == CONFD_STATE_NOT_RUNNING ||
1817 1815 confd_state == CONFD_STATE_OK) {
1818 1816 confd_state = CONFD_STATE_STARTED;
1819 1817 start_syseventconfd();
1820 1818 confd_retries = 0;
1821 1819 rval = EAGAIN;
1822 1820 } else if (confd_state == CONFD_STATE_STARTED &&
1823 1821 confd_retries < 16) {
1824 1822 if (++confd_retries == 16) {
1825 1823 confd_state = CONFD_STATE_ERR;
1826 1824 if (confd_err_msg_emitted == 0) {
1827 1825 syslog(LOG_ERR,
1828 1826 SYSEVENTCONFD_ERR);
1829 1827 confd_err_msg_emitted = 1;
1830 1828 }
1831 1829 }
1832 1830 rval = EAGAIN;
1833 1831 } else {
1834 1832 rval = errno;
1835 1833 }
1836 1834 break;
1837 1835 default:
1838 1836 syslog(LOG_ERR, SYSEVENTCONFD_TRAN_ERR,
1839 1837 strerror(errno));
1840 1838 rval = errno;
1841 1839 break;
1842 1840 }
1843 1841 } else if (confd_state != CONFD_STATE_OK) {
1844 1842 if (confd_state == CONFD_STATE_ERR) {
1845 1843 syslog(LOG_ERR, SYSEVENTCONFD_OK);
1846 1844 confd_err_msg_emitted = 0;
1847 1845 }
1848 1846 confd_state = CONFD_STATE_OK;
1849 1847 confd_retries = 0;
1850 1848 confd_err_msg_emitted = 0;
1851 1849 }
1852 1850 return (rval);
1853 1851 }
1854 1852
1855 1853
1856 1854 /*
1857 1855 * Send events on queue to syseventconfd daemon. We queue events
1858 1856 * here since the daemon is unable to handle events during an
1859 1857 * active fork/exec, returning EAGAIN as a result. It is grossly
1860 1858 * inefficient to bounce these events back to syseventd, so
1861 1859 * we queue them here for delivery.
1862 1860 *
1863 1861 * EAGAIN/EINTR don't indicate errors with the transport to
1864 1862 * syseventconfd itself, just the daemon is busy or some
1865 1863 * other transient difficulty. We retry EBADF and other errors
1866 1864 * for some time, then eventually give up - something's broken.
1867 1865 *
1868 1866 * Error handling strategy:
1869 1867 * If we're trying to shut down and the syseventconfd daemon isn't
1870 1868 * responding, abort the queue so we don't cause the fini to hang
1871 1869 * forever. Otherwise, EAGAIN/EINTR are retried forever, as
1872 1870 * we presume the daemon is active but either busy or some transient
1873 1871 * state is preventing the transport. We make considerable effort
1874 1872 * to retry EBADF since the daemon may take some time to come up when
1875 1873 * restarted so don't want to give up too easily. Once we enter
1876 1874 * the DISABLED state, we stop handling events altogther to
1877 1875 * avoid thrashing the system if the syseventconfd binary is
1878 1876 * corrupted or missing. This state can be cleared by issuing
1879 1877 * a HUP signal to the syseventd daemon. For errors other than
1880 1878 * EAGAIN/EINTR/EBADF, we just drop the event and if we get
1881 1879 * a certain number of these in a row, we enter the DISABLED
1882 1880 * state.
1883 1881 */
1884 1882
1885 1883 static void
1886 1884 transport_queued_events()
1887 1885 {
1888 1886 int rval;
1889 1887 cmdqueue_t *cmd;
1890 1888
1891 1889 (void) mutex_lock(&cmdq_lock);
1892 1890 while (cmdq != NULL) {
1893 1891 cmd = cmdq;
1894 1892 (void) mutex_unlock(&cmdq_lock);
1895 1893 rval = transport_event(cmd->event);
1896 1894 (void) mutex_lock(&cmdq_lock);
1897 1895 if (rval != 0) {
1898 1896 switch (rval) {
1899 1897 case EAGAIN:
1900 1898 case EINTR:
1901 1899 /*
1902 1900 * Limit retries in the case of fini
1903 1901 */
1904 1902 if (want_fini) {
1905 1903 if (++transport_retries == 16) {
1906 1904 abort_cmd_queue();
1907 1905 }
1908 1906 }
1909 1907 (void) mutex_unlock(&cmdq_lock);
1910 1908 return;
1911 1909 case EBADF:
1912 1910 /*
1913 1911 * retry up to 16 times
1914 1912 */
1915 1913 if (want_fini || ++transport_retries == 16) {
1916 1914 abort_cmd_queue();
1917 1915 }
1918 1916 (void) mutex_unlock(&cmdq_lock);
1919 1917 return;
1920 1918 default:
1921 1919 /*
1922 1920 * After 16 sequential errors, give up
1923 1921 */
1924 1922 if (++transport_retries == 16) {
1925 1923 abort_cmd_queue();
1926 1924 (void) mutex_unlock(&cmdq_lock);
1927 1925 return;
1928 1926 }
1929 1927 /*
1930 1928 * We don't retry these errors, we
1931 1929 * fall through to remove this event
1932 1930 * from the queue.
1933 1931 */
1934 1932 break;
1935 1933 }
1936 1934 } else {
1937 1935 transport_retries = 0;
1938 1936 }
1939 1937
1940 1938 /*
1941 1939 * Take completed event off queue
1942 1940 */
1943 1941 cmdq_cnt--;
1944 1942 cmdq = cmdq->next;
1945 1943 if (cmdq == NULL) {
1946 1944 cmdq_tail = NULL;
1947 1945 }
1948 1946 (void) mutex_unlock(&cmdq_lock);
1949 1947 sysevent_free(cmd->event);
1950 1948 sc_free(cmd, sizeof (cmdqueue_t));
1951 1949 (void) mutex_lock(&cmdq_lock);
1952 1950 }
1953 1951
1954 1952 (void) mutex_unlock(&cmdq_lock);
1955 1953 }
1956 1954
1957 1955
1958 1956 static void
1959 1957 queue_flush_thr()
1960 1958 {
1961 1959 int n;
1962 1960
1963 1961 (void) mutex_lock(&cmdq_lock);
1964 1962 for (;;) {
1965 1963 while (cmdq_cnt == 0 && want_fini == 0) {
1966 1964 (void) cond_wait(&cmdq_cv, &cmdq_lock);
1967 1965 }
1968 1966 if (cmdq_cnt == 0 && want_fini) {
1969 1967 (void) cond_signal(&cmdq_thr_cv);
1970 1968 (void) mutex_unlock(&cmdq_lock);
1971 1969 thr_exit(NULL);
1972 1970 /*NOTREACHED*/
1973 1971 }
1974 1972 (void) mutex_unlock(&cmdq_lock);
1975 1973 transport_queued_events();
1976 1974 (void) mutex_lock(&cmdq_lock);
1977 1975 if (cmdq_cnt != 0) {
1978 1976 (void) mutex_unlock(&cmdq_lock);
1979 1977 if (want_fini == 0 && confd_err_msg_emitted) {
1980 1978 for (n = 0; n < 60; n++) {
1981 1979 (void) sleep(1);
1982 1980 if (want_fini)
1983 1981 break;
1984 1982 }
1985 1983 } else {
1986 1984 (void) sleep(1);
1987 1985 }
1988 1986 (void) mutex_lock(&cmdq_lock);
1989 1987 }
1990 1988 }
1991 1989 }
1992 1990
1993 1991
1994 1992 /*
1995 1993 * syseventd daemon module event handler
1996 1994 *
1997 1995 * The syseventd daemon calls this handler with each event
1998 1996 * for this module to handle the event as appropriate.
1999 1997 * The task of this module is to compare the event's
2000 1998 * class/subclass/publisher/vendor against the list of
2001 1999 * event specifications provided in the installed
2002 2000 * sysevent.conf files. Build and execute the
2003 2001 * defined command for that event specification
2004 2002 * for each match.
2005 2003 *
2006 2004 * Events are matched against the class, subclass, vendor
2007 2005 * and publisher specifications. Any field not to be matched
2008 2006 * against an event should be set to '-'. A specification
2009 2007 * of '- - - -' generates a match against every event.
2010 2008 */
2011 2009 /*ARGSUSED*/
2012 2010 static int
2013 2011 sysevent_conf_event(sysevent_t *ev, int flag)
2014 2012 {
2015 2013 int ret = 0;
2016 2014 char *vendor;
2017 2015 char *publisher;
2018 2016 char *class;
2019 2017 char *subclass;
2020 2018 syseventtab_t *sep;
2021 2019 sysevent_hdr_info_t hdr;
2022 2020 uint64_t seq;
2023 2021 hrtime_t ts;
2024 2022
2025 2023 /*
2026 2024 * If we've been completely unable to communicate with
2027 2025 * syseventconfd, there's not much we can do.
2028 2026 */
2029 2027 if (confd_state == CONFD_STATE_DISABLED) {
2030 2028 return (0);
2031 2029 }
2032 2030
2033 2031 /*
2034 2032 * sysevent_get_seq(ev) < ev_seq):
2035 2033 * an event we have played before, ignore it
2036 2034 * sysevent_get_seq(ev) == ev_seq):
2037 2035 * ev_nretries > 0, an event being retried
2038 2036 * sysevent_get_seq(ev) > ev_seq):
2039 2037 * a new event
2040 2038 */
2041 2039 if (debug_level >= DBG_EVENTS) {
2042 2040 if (sysevent_get_seq(ev) == ev_seq && ev_nretries > 0) {
2043 2041 syseventd_print(DBG_EVENTS,
2044 2042 "sequence: %lld/%lld, retry %d\n",
2045 2043 sysevent_get_seq(ev), ev_seq, ev_nretries);
2046 2044 } else if (sysevent_get_seq(ev) > ev_seq) {
2047 2045 syseventd_print(DBG_EVENTS,
2048 2046 "sequence: %lld/%lld\n",
2049 2047 sysevent_get_seq(ev), ev_seq);
2050 2048 }
2051 2049 }
2052 2050
2053 2051 seq = sysevent_get_seq(ev);
2054 2052 sysevent_get_time(ev, &ts);
2055 2053
2056 2054 if (seq > ev_seq || ts > ev_ts) {
2057 2055 ev_nretries = 0;
2058 2056 } else if (first_event == 0 &&
2059 2057 (((seq < ev_seq) || (seq == 0 && ts > ev_ts)) ||
2060 2058 (seq == ev_seq && ev_nretries == 0))) {
2061 2059 syseventd_print(DBG_TEST,
2062 2060 "out-of-order sequence: received %lld/0x%llx, "
2063 2061 "expected %lld/0x%llx\n", seq, ts, ev_seq+1, ev_ts);
2064 2062 return (ret);
2065 2063 }
2066 2064
2067 2065 ev_ts = ts;
2068 2066 ev_seq = seq;
2069 2067 first_event = 0;
2070 2068
2071 2069 /*
2072 2070 * sysevent_get_vendor_name() and sysevent_get_pub_name()
2073 2071 * allocate strings which must be freed.
2074 2072 */
2075 2073 vendor = sysevent_get_vendor_name(ev);
2076 2074 publisher = sysevent_get_pub_name(ev);
2077 2075 class = sysevent_get_class_name(ev);
2078 2076 subclass = sysevent_get_subclass_name(ev);
2079 2077
2080 2078 if (vendor == NULL || publisher == NULL) {
2081 2079 syseventd_print(DBG_EVENTS, "Short on memory with vendor "
2082 2080 "and/or publisher string generation\n");
2083 2081 /* Temporary short on memory */
2084 2082 ev_nretries++;
2085 2083 free(publisher);
2086 2084 free(vendor);
2087 2085 return (EAGAIN);
2088 2086 }
2089 2087
2090 2088 syseventd_print(DBG_EVENTS,
2091 2089 "%s event %lld: vendor='%s' publisher='%s' class='%s' "
2092 2090 "subclass='%s'\n", whoami, sysevent_get_seq(ev), vendor,
2093 2091 publisher, class, subclass);
2094 2092
2095 2093 for (sep = syseventtab; sep; sep = sep->se_next) {
2096 2094 if (strcmp(sep->se_vendor, "-") != 0) {
2097 2095 if (strcmp(sep->se_vendor, vendor) != 0)
2098 2096 continue;
2099 2097 }
2100 2098 if (strcmp(sep->se_publisher, "-") != 0) {
2101 2099 if (strcmp(sep->se_publisher, publisher) != 0)
2102 2100 continue;
2103 2101 }
2104 2102 if (strcmp(sep->se_class, "-") != 0) {
2105 2103 if (strcmp(sep->se_class, class) != 0)
2106 2104 continue;
2107 2105 }
2108 2106 if (strcmp(sep->se_subclass, "-") != 0) {
2109 2107 if (strcmp(sep->se_subclass, subclass) != 0)
2110 2108 continue;
2111 2109 }
2112 2110 syseventd_print(DBG_MATCHES, " event match: %s, line %d\n",
2113 2111 sep->se_conf_file, sep->se_lineno);
2114 2112 hdr.class = class;
2115 2113 hdr.subclass = subclass;
2116 2114 hdr.vendor = vendor;
2117 2115 hdr.publisher = publisher;
2118 2116 if ((ret = queue_event(ev, sep, &hdr)) != 0)
2119 2117 break;
2120 2118 }
2121 2119
2122 2120 if (ret == 0) {
2123 2121 ev_nretries = 0;
2124 2122 } else {
2125 2123 /*
2126 2124 * Ask syseventd to retry any failed event. If we have
2127 2125 * reached the limit on retries, emit a msg that we're
2128 2126 * not going to be able to service it.
2129 2127 */
2130 2128 if (ev_nretries == SE_MAX_RETRY_LIMIT) {
2131 2129 syslog(LOG_ERR, SYSEVENT_SEND_ERR,
2132 2130 sep->se_conf_file, sep->se_lineno, errno);
2133 2131 } else {
2134 2132 syseventd_print(DBG_TEST, "%s event %lld: "
2135 2133 "'%s' '%s' '%s' '%s - errno %d, retry %d\n",
2136 2134 whoami, sysevent_get_seq(ev), vendor,
2137 2135 publisher, class, subclass, errno, ev_nretries);
2138 2136 }
2139 2137 ret = EAGAIN;
2140 2138 ev_nretries++;
2141 2139 }
2142 2140
2143 2141 free(publisher);
2144 2142 free(vendor);
2145 2143
2146 2144 return (ret);
2147 2145 }
2148 2146
2149 2147 /*
2150 2148 * syseventd daemon module initialization
2151 2149 */
2152 2150 struct slm_mod_ops *
2153 2151 slm_init()
2154 2152 {
2155 2153 char lock_file[PATH_MAX+1];
2156 2154 int lock_fd;
2157 2155 int err;
2158 2156
2159 2157 /*
2160 2158 * This functionality is not supported in the mini-root
2161 2159 * environment, ie install. If root_dir is set, implying
2162 2160 * install, we quietly fail. Return dummy ops rather
2163 2161 * than NULL to avoid error msgs out of syseventd.
2164 2162 */
2165 2163 if (strcmp(root_dir, "") != 0) {
2166 2164 return (&sysevent_conf_dummy_mod_ops);
2167 2165 }
2168 2166
2169 2167 ev_nretries = 0;
2170 2168 first_event = 1;
2171 2169
2172 2170 /*
2173 2171 * Initialize the channel to syseventconfd
2174 2172 */
2175 2173 confd_handle = sysevent_open_channel_alt(SYSEVENTCONFD_SERVICE_DOOR);
2176 2174 if (confd_handle == NULL) {
2177 2175 syslog(LOG_ERR, CHANNEL_OPEN_ERR);
2178 2176 return (NULL);
2179 2177 }
2180 2178
2181 2179 if (sysevent_bind_publisher(confd_handle) != 0) {
2182 2180 if (errno == EBUSY) {
2183 2181 sysevent_cleanup_publishers(confd_handle);
2184 2182 if (sysevent_bind_publisher(confd_handle) != 0) {
2185 2183 sysevent_close_channel(confd_handle);
2186 2184 return (NULL);
2187 2185 }
2188 2186 }
2189 2187 }
2190 2188
2191 2189 sysevent_cleanup_subscribers(confd_handle);
2192 2190
2193 2191 cmdq = NULL;
2194 2192 cmdq_tail = NULL;
2195 2193 cmdq_cnt = 0;
2196 2194 want_fini = 0;
2197 2195 confd_err_msg_emitted = 0;
2198 2196 if (confd_state != CONFD_STATE_OK) {
2199 2197 confd_state = CONFD_STATE_NOT_RUNNING;
2200 2198 }
2201 2199
2202 2200 confd_retries = 0;
2203 2201 transport_retries = 0;
2204 2202
2205 2203 (void) mutex_init(&cmdq_lock, USYNC_THREAD, NULL);
2206 2204 (void) cond_init(&cmdq_cv, USYNC_THREAD, NULL);
2207 2205 (void) cond_init(&cmdq_thr_cv, USYNC_THREAD, NULL);
2208 2206
2209 2207 /*
2210 2208 * Create thread to flush cmd queue
2211 2209 */
2212 2210 if ((err = thr_create(NULL, NULL, (void *(*)(void*))queue_flush_thr,
2213 2211 (void *)NULL, 0, &cmdq_thr_id)) != 0) {
2214 2212 syslog(LOG_ERR, THR_CREATE_ERR, strerror(err));
2215 2213 sysevent_close_channel(confd_handle);
2216 2214 confd_handle = NULL;
2217 2215 (void) mutex_destroy(&cmdq_lock);
2218 2216 (void) cond_destroy(&cmdq_cv);
2219 2217 (void) cond_destroy(&cmdq_thr_cv);
2220 2218 return (NULL);
2221 2219 }
2222 2220
2223 2221 if ((lock_fd = enter_lock(lock_file)) == -1) {
2224 2222 (void) thr_join(cmdq_thr_id, NULL, NULL);
2225 2223 sysevent_close_channel(confd_handle);
2226 2224 confd_handle = NULL;
2227 2225 (void) mutex_destroy(&cmdq_lock);
2228 2226 (void) cond_destroy(&cmdq_cv);
2229 2227 (void) cond_destroy(&cmdq_thr_cv);
2230 2228 return (NULL);
2231 2229 }
2232 2230
2233 2231 build_event_table();
2234 2232 exit_lock(lock_fd, lock_file);
2235 2233 return (&sysevent_conf_mod_ops);
2236 2234 }
2237 2235
2238 2236 /*
2239 2237 * syseventd daemon module tear-down
2240 2238 */
2241 2239 void
2242 2240 slm_fini()
2243 2241 {
2244 2242 int err;
2245 2243
2246 2244 /*
2247 2245 * Nothing to clean up if we're in the install environment
2248 2246 */
2249 2247 if (strcmp(root_dir, "") != 0) {
2250 2248 return;
2251 2249 }
2252 2250
2253 2251 /*
2254 2252 * Wait for the queue to drain
2255 2253 */
2256 2254 (void) mutex_lock(&cmdq_lock);
2257 2255 want_fini = 1;
2258 2256 (void) cond_signal(&cmdq_cv);
2259 2257 (void) cond_wait(&cmdq_thr_cv, &cmdq_lock);
2260 2258 (void) mutex_unlock(&cmdq_lock);
2261 2259
2262 2260 /*
2263 2261 * Shut down the the queue flush thread
2264 2262 */
2265 2263 if ((err = thr_join(cmdq_thr_id, NULL, NULL)) != 0) {
2266 2264 syslog(LOG_ERR, THR_JOIN_ERR, strerror(err));
2267 2265 }
2268 2266
2269 2267 sysevent_close_channel(confd_handle);
2270 2268 confd_handle = NULL;
2271 2269 (void) mutex_destroy(&cmdq_lock);
2272 2270 (void) cond_destroy(&cmdq_cv);
2273 2271 (void) cond_destroy(&cmdq_thr_cv);
2274 2272 free_event_table();
2275 2273 }
2276 2274
2277 2275 /*ARGSUSED*/
2278 2276 static int
2279 2277 sysevent_conf_dummy_event(sysevent_t *ev, int flag)
2280 2278 {
2281 2279 return (0);
2282 2280 }
↓ open down ↓ |
568 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX