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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * syseventadm - command to administer the sysevent.conf registry
28 * - administers the general purpose event framework
30 * The current implementation of the registry using files in
31 * /etc/sysevent/config, files are named as event specifications
32 * are added with the combination of the vendor, publisher, event
33 * class and subclass strings:
35 * [<vendor>,][<publisher>,][<class>,]sysevent.conf
40 #include <sys/types.h>
58 #include <libsysevent.h>
60 #include <sys/sysevent_impl.h>
61 #include <sys/modctl.h>
62 #include <sys/param.h>
64 #include <sys/systeminfo.h>
67 #include "syseventadm.h"
68 #include "syseventadm_msg.h"
72 #define assert(EX) ((void)0)
75 static char *whoami
= NULL
;
76 static char *root_dir
= "";
78 static char *arg_vendor
= NULL
;
79 static char *arg_publisher
= NULL
;
80 static char *arg_class
= NULL
;
81 static char *arg_subclass
= NULL
;
82 static char *arg_username
= NULL
;
83 static char *arg_path
= NULL
;
84 static int arg_nargs
= 0;
85 static char **arg_args
= NULL
;
88 static char lock_file
[PATH_MAX
+ 1];
96 (void) fprintf(stderr
, MSG_USAGE_INTRO
);
97 (void) fprintf(stderr
, MSG_USAGE_OPTIONS
);
98 (void) fprintf(stderr
, "\n"
99 "\tsyseventadm add ...\n"
100 "\tsyseventadm remove ...\n"
101 "\tsyseventadm list ...\n"
102 "\tsyseventadm restart\n"
103 "\tsyseventadm help\n");
109 serve_syseventdotconf(int argc
, char **argv
, char *cmd
)
114 while ((c
= getopt(argc
, argv
, "R:v:p:c:s:u:")) != EOF
) {
118 * Alternate root path for install, etc.
120 set_root_dir(optarg
);
126 arg_publisher
= optarg
;
132 arg_subclass
= optarg
;
135 arg_username
= optarg
;
143 arg_path
= argv
[optind
++];
145 arg_nargs
= argc
- optind
;
146 arg_args
= argv
+ optind
;
150 enter_lock(root_dir
);
152 if (strcmp(cmd
, "add") == 0) {
154 } else if (strcmp(cmd
, "list") == 0) {
155 rval
= list_remove_cmd(CMD_LIST
);
156 } else if (strcmp(cmd
, "remove") == 0) {
157 rval
= list_remove_cmd(CMD_REMOVE
);
158 } else if (strcmp(cmd
, "restart") == 0) {
159 rval
= restart_cmd();
171 main(int argc
, char **argv
)
177 (void) setlocale(LC_ALL
, "");
178 (void) textdomain(TEXT_DOMAIN
);
180 if ((whoami
= strrchr(argv
[0], '/')) == NULL
) {
187 return (usage_gen());
190 cmd
= argv
[optind
++];
192 /* Allow non-privileged users to get the help messages */
193 if (strcmp(cmd
, "help") == 0) {
199 (void) fprintf(stderr
, MSG_NOT_ROOT
, whoami
);
203 if (strcmp(cmd
, "evc") != 0 && getzoneid() != GLOBAL_ZONEID
) {
204 (void) fprintf(stderr
, MSG_NOT_GLOBAL
, whoami
);
208 if (strcmp(cmd
, "add") == 0 ||
209 strcmp(cmd
, "remove") == 0 || strcmp(cmd
, "list") == 0 ||
210 strcmp(cmd
, "restart") == 0) {
211 rval
= serve_syseventdotconf(argc
, argv
, cmd
);
220 enter_lock(char *root_dir
)
224 if (snprintf(lock_file
, sizeof (lock_file
), "%s%s", root_dir
,
225 LOCK_FILENAME
) >= sizeof (lock_file
)) {
226 (void) fprintf(stderr
, MSG_LOCK_PATH_ERR
, whoami
, lock_file
);
227 exit(EXIT_CMD_FAILED
);
229 lock_fd
= open(lock_file
, O_CREAT
|O_RDWR
, 0644);
231 (void) fprintf(stderr
, MSG_LOCK_CREATE_ERR
,
232 whoami
, lock_file
, strerror(errno
));
233 exit(EXIT_CMD_FAILED
);
236 lock
.l_type
= F_WRLCK
;
237 lock
.l_whence
= SEEK_SET
;
242 if (fcntl(lock_fd
, F_SETLKW
, &lock
) == -1) {
243 if (errno
== EAGAIN
|| errno
== EINTR
)
245 (void) close(lock_fd
);
246 (void) fprintf(stderr
, MSG_LOCK_SET_ERR
,
247 whoami
, lock_file
, strerror(errno
));
248 exit(EXIT_CMD_FAILED
);
258 lock
.l_type
= F_UNLCK
;
259 lock
.l_whence
= SEEK_SET
;
263 if (fcntl(lock_fd
, F_SETLK
, &lock
) == -1) {
264 (void) fprintf(stderr
, MSG_LOCK_CLR_ERR
,
265 whoami
, lock_file
, strerror(errno
));
268 if (close(lock_fd
) == -1) {
269 (void) fprintf(stderr
, MSG_LOCK_CLOSE_ERR
,
270 whoami
, lock_file
, strerror(errno
));
276 set_root_dir(char *dir
)
278 root_dir
= sc_strdup(dir
);
282 static char *usage_msg
[] = {
284 "\tsyseventadm add [-R <rootdir>] [-v vendor] [-p publisher]\n"
285 "\t[-c class] [-s subclass] [-u username] path [args]\n"
287 "\tsyseventadm remove [-R <rootdir>] [-v vendor] [-p publisher]\n"
288 "\t[-c class] [-s subclass] [-u username] [path [args]]\n"
290 "\tsyseventadm list [-R <rootdir>] [-v vendor] [-p publisher]\n"
291 "\t[-c class] [-s subclass] [-u username] [path [args]]\n"
301 for (i
= 0; i
< sizeof (usage_msg
)/sizeof (char *); i
++) {
302 (void) fputs(*msgs
++, stderr
);
312 char fname
[MAXPATHLEN
+1];
321 * At least one of vendor/publisher/class must be specified.
322 * Subclass is only defined within the context of class.
323 * For add, path must also be specified.
332 if (noptions
== 0 || (arg_subclass
&& arg_class
== NULL
)) {
336 if (arg_path
== NULL
)
340 * Generate the sysevent.conf file name
342 (void) strcpy(fname
, root_dir
);
343 (void) strcat(fname
, SYSEVENT_CONFIG_DIR
);
344 (void) strcat(fname
, "/");
347 (void) strcat(fname
, arg_vendor
);
352 (void) strcat(fname
, ",");
353 (void) strcat(fname
, arg_publisher
);
358 (void) strcat(fname
, ",");
359 (void) strcat(fname
, arg_class
);
361 (void) strcat(fname
, SYSEVENT_CONF_SUFFIX
);
364 * Prepare the line to be written to the sysevent.conf file
368 strcats(line
, arg_class
== NULL
? "-" : arg_class
);
371 strcats(line
, arg_subclass
== NULL
? "-" : arg_subclass
);
374 strcats(line
, arg_vendor
== NULL
? "-" : arg_vendor
);
377 strcats(line
, arg_publisher
== NULL
? "-" : arg_publisher
);
380 strcats(line
, arg_username
== NULL
? "-" : arg_username
);
383 strcats(line
, "- - ");
384 strcats(line
, arg_path
);
387 for (i
= 0; i
< arg_nargs
; i
++) {
389 strcats(line
, arg_args
[i
]);
393 if (stat(fname
, &st
) == -1) {
394 if (creat(fname
, 0644) == -1) {
395 (void) fprintf(stderr
, MSG_CANNOT_CREATE
,
396 whoami
, fname
, strerror(errno
));
398 return (EXIT_CMD_FAILED
);
402 fp
= fopen(fname
, "a");
404 (void) fprintf(stderr
, MSG_CANNOT_OPEN
,
405 whoami
, fname
, strerror(errno
));
407 return (EXIT_CMD_FAILED
);
410 (void) fprintf(fp
, "%s\n", line
->s_str
);
413 if (fclose(fp
) == -1) {
414 (void) fprintf(stderr
, MSG_CLOSE_ERROR
,
415 whoami
, fname
, strerror(errno
));
416 return (EXIT_CMD_FAILED
);
419 if (chmod(fname
, 0444) == -1) {
420 (void) fprintf(stderr
, MSG_CHMOD_ERROR
,
421 whoami
, fname
, strerror(errno
));
422 return (EXIT_CMD_FAILED
);
429 list_remove_cmd(int cmd
)
433 char path
[MAXPATHLEN
+1];
434 char fname
[MAXPATHLEN
+1];
436 char **dirlist
= NULL
;
444 * For the remove cmd, at least one of vendor/publisher/class/username
445 * path must be specified. Subclass is only defined within the
446 * context of a class.
448 if (cmd
== CMD_REMOVE
) {
460 if (noptions
== 0 || (arg_subclass
&& arg_class
== NULL
)) {
465 (void) strcpy(path
, root_dir
);
466 (void) strcat(path
, SYSEVENT_CONFIG_DIR
);
468 if ((dir
= opendir(path
)) == NULL
) {
469 (void) fprintf(stderr
, MSG_CANNOT_OPEN_DIR
,
470 whoami
, path
, strerror(errno
));
471 return (EXIT_CMD_FAILED
);
474 while ((dp
= readdir(dir
)) != NULL
) {
475 if (dp
->d_name
[0] == '.')
477 if ((strlen(dp
->d_name
) == 0) ||
478 (strcmp(dp
->d_name
, "lost+found") == 0))
480 suffix
= strrchr(dp
->d_name
, ',');
481 if (suffix
&& strcmp(suffix
, SYSEVENT_CONF_SUFFIX
) == 0) {
482 (void) strcpy(fname
, path
);
483 (void) strcat(fname
, "/");
484 (void) strcat(fname
, dp
->d_name
);
485 dirlist
= build_strlist(dirlist
,
486 &list_size
, &list_alloc
, fname
);
490 if (closedir(dir
) == -1) {
491 (void) fprintf(stderr
, MSG_CLOSE_DIR_ERROR
,
492 whoami
, path
, strerror(errno
));
493 return (EXIT_CMD_FAILED
);
496 rval
= EXIT_NO_MATCH
;
498 for (p
= dirlist
; *p
!= NULL
; p
++) {
501 result
= list_file(*p
);
504 result
= remove_file(*p
);
507 if (rval
== EXIT_NO_MATCH
&&
508 result
!= EXIT_NO_MATCH
)
517 list_file(char *fname
)
522 int rval
= EXIT_NO_MATCH
;
524 fp
= fopen(fname
, "r");
526 (void) fprintf(stderr
, MSG_CANNOT_OPEN
,
527 whoami
, fname
, strerror(errno
));
528 return (EXIT_CMD_FAILED
);
531 line
= read_next_line(fp
);
534 sep
= parse_line(line
);
536 if (matches_serecord(sep
)) {
537 print_serecord(stdout
, sep
);
551 remove_file(char *fname
)
558 char tmp_name
[MAXPATHLEN
+1];
561 fp
= fopen(fname
, "r");
563 (void) fprintf(stderr
, MSG_CANNOT_OPEN
,
564 whoami
, fname
, strerror(errno
));
565 return (EXIT_CMD_FAILED
);
568 if (check_for_removes(fp
) == 0) {
570 return (EXIT_NO_MATCH
);
575 (void) strcpy(tmp_name
, root_dir
);
576 (void) strcat(tmp_name
, SYSEVENT_CONFIG_DIR
);
577 (void) strcat(tmp_name
, "/tmp.XXXXXX");
578 if (mktemp(tmp_name
) == NULL
) {
579 (void) fprintf(stderr
, "unable to make tmp file name\n");
580 return (EXIT_CMD_FAILED
);
583 if (creat(tmp_name
, 0644) == -1) {
584 (void) fprintf(stderr
, MSG_CANNOT_CREATE
,
585 whoami
, tmp_name
, strerror(errno
));
586 return (EXIT_CMD_FAILED
);
589 tmp_fp
= fopen(tmp_name
, "a");
590 if (tmp_fp
== NULL
) {
591 (void) fprintf(stderr
, MSG_CANNOT_OPEN
,
592 whoami
, tmp_name
, strerror(errno
));
593 (void) unlink(tmp_name
);
595 return (EXIT_CMD_FAILED
);
599 line
= read_next_line(fp
);
602 raw_line
= sc_strdup(line
->s_str
);
603 sep
= parse_line(line
);
605 (void) fputs(line
->s_str
, tmp_fp
);
607 if (!matches_serecord(sep
)) {
609 (void) fprintf(tmp_fp
, "%s\n", raw_line
);
614 sc_strfree(raw_line
);
617 if (fclose(tmp_fp
) == -1) {
618 (void) fprintf(stderr
, MSG_CLOSE_ERROR
,
619 whoami
, tmp_name
, strerror(errno
));
623 if (unlink(tmp_name
) == -1) {
624 (void) fprintf(stderr
, MSG_CANNOT_UNLINK
,
625 whoami
, tmp_name
, strerror(errno
));
626 return (EXIT_CMD_FAILED
);
628 if (unlink(fname
) == -1) {
629 (void) fprintf(stderr
, MSG_CANNOT_UNLINK
,
630 whoami
, fname
, strerror(errno
));
631 return (EXIT_CMD_FAILED
);
634 if (unlink(fname
) == -1) {
635 (void) fprintf(stderr
, MSG_CANNOT_UNLINK
,
636 whoami
, fname
, strerror(errno
));
637 return (EXIT_CMD_FAILED
);
639 if (rename(tmp_name
, fname
) == -1) {
640 (void) fprintf(stderr
, MSG_CANNOT_RENAME
,
641 whoami
, tmp_name
, fname
, strerror(errno
));
642 return (EXIT_CMD_FAILED
);
644 if (chmod(fname
, 0444) == -1) {
645 (void) fprintf(stderr
, MSG_CHMOD_ERROR
,
646 whoami
, fname
, strerror(errno
));
647 return (EXIT_CMD_FAILED
);
655 check_for_removes(FILE *fp
)
661 line
= read_next_line(fp
);
664 sep
= parse_line(line
);
666 if (matches_serecord(sep
)) {
681 matches_serecord(serecord_t
*sep
)
689 strcmp(arg_vendor
, sep
->se_vendor
) != 0) {
694 strcmp(arg_publisher
, sep
->se_publisher
) != 0) {
699 strcmp(arg_class
, sep
->se_class
) != 0) {
704 strcmp(arg_subclass
, sep
->se_subclass
) != 0) {
709 strcmp(arg_username
, sep
->se_user
) != 0) {
714 strcmp(arg_path
, sep
->se_path
) != 0) {
719 line
= sc_strdup(sep
->se_args
);
721 for (i
= 0; i
< arg_nargs
; i
++) {
722 token
= next_field(&lp
);
723 if (strcmp(arg_args
[i
], token
) != 0) {
735 print_serecord(FILE *fp
, serecord_t
*sep
)
741 if (strcmp(sep
->se_vendor
, "-") != 0) {
742 strcats(line
, "vendor=");
743 strcats(line
, sep
->se_vendor
);
746 if (strcmp(sep
->se_publisher
, "-") != 0) {
747 strcats(line
, "publisher=");
748 strcats(line
, sep
->se_publisher
);
751 if (strcmp(sep
->se_class
, "-") != 0) {
752 strcats(line
, "class=");
753 strcats(line
, sep
->se_class
);
755 if (strcmp(sep
->se_subclass
, "-") != 0) {
756 strcats(line
, "subclass=");
757 strcats(line
, sep
->se_subclass
);
761 if (strcmp(sep
->se_user
, "-") != 0) {
762 strcats(line
, "username=");
763 strcats(line
, sep
->se_user
);
766 strcats(line
, sep
->se_path
);
769 strcats(line
, sep
->se_args
);
773 (void) fputs(line
->s_str
, fp
);
783 if (system("pkill -HUP syseventd") == -1) {
784 (void) fprintf(stderr
, MSG_RESTART_FAILED
,
785 whoami
, strerror(errno
));
786 return (EXIT_CMD_FAILED
);
793 read_next_line(FILE *fp
)
800 lp
= fstrgets(line
, fp
);
806 *(lp
+ strlen(lp
)-1) = 0;
812 parse_line(str_t
*line
)
815 char *vendor
, *publisher
;
816 char *class, *subclass
;
818 char *reserved1
, *reserved2
;
823 if (*lp
== 0 || *lp
== '#') {
827 if ((class = next_field(&lp
)) != NULL
) {
828 subclass
= next_field(&lp
);
831 vendor
= next_field(&lp
);
834 publisher
= next_field(&lp
);
837 user
= next_field(&lp
);
840 reserved1
= next_field(&lp
);
843 reserved2
= next_field(&lp
);
846 path
= next_field(&lp
);
849 args
= skip_spaces(&lp
);
852 sep
= sc_malloc(sizeof (serecord_t
));
854 sep
->se_vendor
= sc_strdup(vendor
);
855 sep
->se_publisher
= sc_strdup(publisher
);
856 sep
->se_class
= sc_strdup(class);
857 sep
->se_subclass
= sc_strdup(subclass
);
858 sep
->se_user
= sc_strdup(user
);
859 sep
->se_reserved1
= sc_strdup(reserved1
);
860 sep
->se_reserved2
= sc_strdup(reserved2
);
861 sep
->se_path
= sc_strdup(path
);
862 sep
->se_args
= (args
== NULL
) ? NULL
: sc_strdup(args
);
869 free_serecord(serecord_t
*sep
)
871 sc_strfree(sep
->se_vendor
);
872 sc_strfree(sep
->se_publisher
);
873 sc_strfree(sep
->se_class
);
874 sc_strfree(sep
->se_subclass
);
875 sc_strfree(sep
->se_user
);
876 sc_strfree(sep
->se_reserved1
);
877 sc_strfree(sep
->se_reserved2
);
878 sc_strfree(sep
->se_path
);
879 sc_strfree(sep
->se_args
);
880 sc_free(sep
, sizeof (serecord_t
));
885 * skip_spaces() - skip to next non-space character
888 skip_spaces(char **cpp
)
892 while (*cp
== ' ' || *cp
== '\t')
903 * Get next white-space separated field.
904 * next_field() will not check any characters on next line.
905 * Each entry is composed of a single line.
908 next_field(char **cpp
)
913 while (*cp
== ' ' || *cp
== '\t')
920 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
931 * The following functions are simple wrappers/equivalents
932 * for malloc, realloc, free, strdup and a special free
950 sc_realloc(void *p
, size_t current
, size_t n
)
962 sc_free(void *p
, size_t n
)
973 new = malloc((unsigned)(strlen(cp
) + 1));
977 (void) strcpy(new, cp
);
991 * The following functions provide some simple dynamic string
992 * capability. This module has no hard-coded maximum string
993 * lengths and should be able to parse and generate arbitrarily
994 * long strings, macro expansion and command lines.
996 * Each string must be explicitly allocated and freed.
1000 * Allocate a dynamic string, with a hint to indicate how
1001 * much memory to dynamically add to the string as it grows
1002 * beyond its existing bounds, so as to avoid excessive
1003 * reallocs as a string grows.
1010 str
= sc_malloc(sizeof (str_t
));
1020 * Free a dynamically-allocated string
1026 sc_free(str
->s_str
, str
->s_alloc
);
1028 sc_free(str
, sizeof (str_t
));
1033 * Reset a dynamically-allocated string, allows reuse
1034 * rather than freeing the old and allocating a new one.
1037 resetstr(str_t
*str
)
1044 * Concatenate a (simple) string onto a dynamically-allocated string
1047 strcats(str_t
*str
, char *s
)
1050 int len
= str
->s_len
+ strlen(s
) + 1;
1052 if (str
->s_alloc
< len
) {
1053 new_str
= (str
->s_str
== NULL
) ? sc_malloc(len
+str
->s_hint
) :
1054 sc_realloc(str
->s_str
, str
->s_alloc
, len
+str
->s_hint
);
1055 str
->s_str
= new_str
;
1056 str
->s_alloc
= len
+ str
->s_hint
;
1058 (void) strcpy(str
->s_str
+ str
->s_len
, s
);
1059 str
->s_len
= len
- 1;
1064 * Concatenate a character onto a dynamically-allocated string
1067 strcatc(str_t
*str
, int c
)
1070 int len
= str
->s_len
+ 2;
1072 if (str
->s_alloc
< len
) {
1073 new_str
= (str
->s_str
== NULL
) ? sc_malloc(len
+str
->s_hint
) :
1074 sc_realloc(str
->s_str
, str
->s_alloc
, len
+str
->s_hint
);
1075 str
->s_str
= new_str
;
1076 str
->s_alloc
= len
+ str
->s_hint
;
1078 *(str
->s_str
+ str
->s_len
) = (char)c
;
1079 *(str
->s_str
+ str
->s_len
+ 1) = 0;
1084 * fgets() equivalent using a dynamically-allocated string
1087 fstrgets(str_t
*line
, FILE *fp
)
1092 while ((c
= fgetc(fp
)) != EOF
) {
1097 if (line
->s_len
== 0)
1099 return (line
->s_str
);
1104 #define INITIAL_LISTSIZE 4
1105 #define INCR_LISTSIZE 4
1116 if (*size
+ 1 > *alloc
) {
1118 *alloc
= INITIAL_LISTSIZE
;
1119 n
= sizeof (char *) * (*alloc
+ 1);
1120 argvlist
= (char **)malloc(n
);
1121 if (argvlist
== NULL
)
1124 *alloc
+= INCR_LISTSIZE
;
1125 n
= sizeof (char *) * (*alloc
+ 1);
1126 argvlist
= (char **)realloc(argvlist
, n
);
1127 if (argvlist
== NULL
)
1132 argvlist
[*size
] = strdup(str
);
1134 argvlist
[*size
] = NULL
;
1142 (void) fprintf(stderr
, MSG_NO_MEM
, whoami
);