summaryrefslogtreecommitdiff
path: root/usr/src/cmd/syseventadm
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/syseventadm
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/syseventadm')
-rw-r--r--usr/src/cmd/syseventadm/Makefile67
-rw-r--r--usr/src/cmd/syseventadm/syseventadm.c1149
-rw-r--r--usr/src/cmd/syseventadm/syseventadm.h138
-rw-r--r--usr/src/cmd/syseventadm/syseventadm_msg.h103
4 files changed, 1457 insertions, 0 deletions
diff --git a/usr/src/cmd/syseventadm/Makefile b/usr/src/cmd/syseventadm/Makefile
new file mode 100644
index 0000000000..554002269a
--- /dev/null
+++ b/usr/src/cmd/syseventadm/Makefile
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/syseventadm/Makefile
+#
+
+PROG = syseventadm
+
+SRCS = $(PROG).c
+OBJS = $(PROG).o
+
+include ../Makefile.cmd
+
+OWNER= root
+GROUP= sys
+FILEMODE= 0555
+
+POFILES = $(SRCS:.c=.po)
+
+all:= TARGET= all
+install:= TARGET= install
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+lint:= TARGET= lint
+_msg:= TARGET= _msg
+
+
+.KEEP_STATE:
+
+
+all: $(PROG)
+
+install: all $(ROOTUSRSBINPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+FRC:
+
+include ../Makefile.targ
+
diff --git a/usr/src/cmd/syseventadm/syseventadm.c b/usr/src/cmd/syseventadm/syseventadm.c
new file mode 100644
index 0000000000..5d17367ac1
--- /dev/null
+++ b/usr/src/cmd/syseventadm/syseventadm.c
@@ -0,0 +1,1149 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * syseventadm - command to administer the sysevent.conf registry
+ * - administers the general purpose event framework
+ *
+ * The current implementation of the registry using files in
+ * /etc/sysevent/config, files are named as event specifications
+ * are added with the combination of the vendor, publisher, event
+ * class and subclass strings:
+ *
+ * [<vendor>,][<publisher>,][<class>,]sysevent.conf
+ *
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <strings.h>
+#include <unistd.h>
+#include <synch.h>
+#include <syslog.h>
+#include <thread.h>
+#include <limits.h>
+#include <locale.h>
+#include <assert.h>
+#include <libsysevent.h>
+#include <zone.h>
+#include <sys/sysevent_impl.h>
+#include <sys/modctl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/wait.h>
+
+#include "syseventadm.h"
+#include "syseventadm_msg.h"
+
+#ifndef DEBUG
+#undef assert
+#define assert(EX) ((void)0)
+#endif
+
+static char *whoami = NULL;
+static char *root_dir = "";
+
+static char *arg_vendor = NULL;
+static char *arg_publisher = NULL;
+static char *arg_class = NULL;
+static char *arg_subclass = NULL;
+static char *arg_username = NULL;
+static char *arg_path = NULL;
+static int arg_nargs = 0;
+static char **arg_args = NULL;
+
+static int lock_fd;
+static char lock_file[PATH_MAX + 1];
+
+extern char *optarg;
+extern int optind;
+
+static int
+usage_gen()
+{
+ (void) fprintf(stderr, MSG_USAGE_INTRO);
+ (void) fprintf(stderr, MSG_USAGE_OPTIONS);
+ (void) fprintf(stderr, "\n"
+ "\tsyseventadm add ...\n"
+ "\tsyseventadm remove ...\n"
+ "\tsyseventadm list ...\n"
+ "\tsyseventadm restart\n"
+ "\tsyseventadm help\n");
+
+ return (EXIT_USAGE);
+}
+
+static int
+serve_syseventdotconf(int argc, char **argv, char *cmd)
+{
+ int c;
+ int rval;
+
+ while ((c = getopt(argc, argv, "R:v:p:c:s:u:")) != EOF) {
+ switch (c) {
+ case 'R':
+ /*
+ * Alternate root path for install, etc.
+ */
+ set_root_dir(optarg);
+ break;
+ case 'v':
+ arg_vendor = optarg;
+ break;
+ case 'p':
+ arg_publisher = optarg;
+ break;
+ case 'c':
+ arg_class = optarg;
+ break;
+ case 's':
+ arg_subclass = optarg;
+ break;
+ case 'u':
+ arg_username = optarg;
+ break;
+ default:
+ return (usage());
+ }
+ }
+
+ if (optind < argc) {
+ arg_path = argv[optind++];
+ if (optind < argc) {
+ arg_nargs = argc - optind;
+ arg_args = argv + optind;
+ }
+ }
+
+ enter_lock(root_dir);
+
+ if (strcmp(cmd, "add") == 0) {
+ rval = add_cmd();
+ } else if (strcmp(cmd, "list") == 0) {
+ rval = list_remove_cmd(CMD_LIST);
+ } else if (strcmp(cmd, "remove") == 0) {
+ rval = list_remove_cmd(CMD_REMOVE);
+ } else if (strcmp(cmd, "restart") == 0) {
+ rval = restart_cmd();
+ } else {
+ rval = usage();
+ }
+
+ exit_lock();
+
+ return (rval);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ char *cmd;
+ int rval;
+
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ if ((whoami = strrchr(argv[0], '/')) == NULL) {
+ whoami = argv[0];
+ } else {
+ whoami++;
+ }
+
+ if (argc == 1) {
+ return (usage_gen());
+ }
+
+ cmd = argv[optind++];
+
+ /* Allow non-privileged users to get the help messages */
+ if (strcmp(cmd, "help") == 0) {
+ rval = usage_gen();
+ return (rval);
+ }
+
+ if (getuid() != 0) {
+ (void) fprintf(stderr, MSG_NOT_ROOT, whoami);
+ exit(EXIT_PERM);
+ }
+
+ if (strcmp(cmd, "evc") != 0 && getzoneid() != GLOBAL_ZONEID) {
+ (void) fprintf(stderr, MSG_NOT_GLOBAL, whoami);
+ exit(EXIT_PERM);
+ }
+
+ if (strcmp(cmd, "add") == 0 ||
+ strcmp(cmd, "remove") == 0 || strcmp(cmd, "list") == 0 ||
+ strcmp(cmd, "restart") == 0) {
+ rval = serve_syseventdotconf(argc, argv, cmd);
+ } else {
+ rval = usage_gen();
+ }
+ return (rval);
+}
+
+
+static void
+enter_lock(char *root_dir)
+{
+ struct flock lock;
+
+ if (snprintf(lock_file, sizeof (lock_file), "%s%s/%s", root_dir,
+ SYSEVENT_CONFIG_DIR, LOCK_FILENAME) >= sizeof (lock_file)) {
+ (void) fprintf(stderr, MSG_LOCK_PATH_ERR, whoami, lock_file);
+ exit(EXIT_CMD_FAILED);
+ }
+ lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
+ if (lock_fd < 0) {
+ (void) fprintf(stderr, MSG_LOCK_CREATE_ERR,
+ whoami, lock_file, strerror(errno));
+ exit(EXIT_CMD_FAILED);
+ }
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+retry:
+ if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ goto retry;
+ (void) close(lock_fd);
+ (void) fprintf(stderr, MSG_LOCK_SET_ERR,
+ whoami, lock_file, strerror(errno));
+ exit(EXIT_CMD_FAILED);
+ }
+}
+
+
+static void
+exit_lock()
+{
+ struct flock lock;
+
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ if (fcntl(lock_fd, F_SETLK, &lock) == -1) {
+ (void) fprintf(stderr, MSG_LOCK_CLR_ERR,
+ whoami, lock_file, strerror(errno));
+ }
+
+ if (close(lock_fd) == -1) {
+ (void) fprintf(stderr, MSG_LOCK_CLOSE_ERR,
+ whoami, lock_file, strerror(errno));
+ }
+}
+
+
+static void
+set_root_dir(char *dir)
+{
+ root_dir = sc_strdup(dir);
+}
+
+
+static char *usage_msg[] = {
+ "\n"
+ "\tsyseventadm add [-R <rootdir>] [-v vendor] [-p publisher]\n"
+ "\t[-c class] [-s subclass] [-u username] path [args]\n"
+ "\n"
+ "\tsyseventadm remove [-R <rootdir>] [-v vendor] [-p publisher]\n"
+ "\t[-c class] [-s subclass] [-u username] [path [args]]\n"
+ "\n"
+ "\tsyseventadm list [-R <rootdir>] [-v vendor] [-p publisher]\n"
+ "\t[-c class] [-s subclass] [-u username] [path [args]]\n"
+};
+
+static int
+usage()
+{
+ char **msgs;
+ int i;
+
+ msgs = usage_msg;
+ for (i = 0; i < sizeof (usage_msg)/sizeof (char *); i++) {
+ (void) fputs(*msgs++, stderr);
+ }
+
+ return (EXIT_USAGE);
+}
+
+
+static int
+add_cmd(void)
+{
+ char fname[MAXPATHLEN+1];
+ int need_comma = 0;
+ int noptions = 0;
+ struct stat st;
+ FILE *fp;
+ str_t *line;
+ int i;
+
+ /*
+ * At least one of vendor/publisher/class must be specified.
+ * Subclass is only defined within the context of class.
+ * For add, path must also be specified.
+ */
+ if (arg_vendor)
+ noptions++;
+ if (arg_publisher)
+ noptions++;
+ if (arg_class)
+ noptions++;
+
+ if (noptions == 0 || (arg_subclass && arg_class == NULL)) {
+ return (usage());
+ }
+
+ if (arg_path == NULL)
+ return (usage());
+
+ /*
+ * Generate the sysevent.conf file name
+ */
+ (void) strcpy(fname, root_dir);
+ (void) strcat(fname, SYSEVENT_CONFIG_DIR);
+ (void) strcat(fname, "/");
+
+ if (arg_vendor) {
+ (void) strcat(fname, arg_vendor);
+ need_comma = 1;
+ }
+ if (arg_publisher) {
+ if (need_comma)
+ (void) strcat(fname, ",");
+ (void) strcat(fname, arg_publisher);
+ need_comma = 1;
+ }
+ if (arg_class) {
+ if (need_comma)
+ (void) strcat(fname, ",");
+ (void) strcat(fname, arg_class);
+ }
+ (void) strcat(fname, SYSEVENT_CONF_SUFFIX);
+
+ /*
+ * Prepare the line to be written to the sysevent.conf file
+ */
+ line = initstr(128);
+
+ strcats(line, arg_class == NULL ? "-" : arg_class);
+ strcatc(line, ' ');
+
+ strcats(line, arg_subclass == NULL ? "-" : arg_subclass);
+ strcatc(line, ' ');
+
+ strcats(line, arg_vendor == NULL ? "-" : arg_vendor);
+ strcatc(line, ' ');
+
+ strcats(line, arg_publisher == NULL ? "-" : arg_publisher);
+ strcatc(line, ' ');
+
+ strcats(line, arg_username == NULL ? "-" : arg_username);
+ strcatc(line, ' ');
+
+ strcats(line, "- - ");
+ strcats(line, arg_path);
+
+ if (arg_nargs) {
+ for (i = 0; i < arg_nargs; i++) {
+ strcatc(line, ' ');
+ strcats(line, arg_args[i]);
+ }
+ }
+
+ if (stat(fname, &st) == -1) {
+ if (creat(fname, 0644) == -1) {
+ (void) fprintf(stderr, MSG_CANNOT_CREATE,
+ whoami, fname, strerror(errno));
+ freestr(line);
+ return (EXIT_CMD_FAILED);
+ }
+ }
+
+ fp = fopen(fname, "a");
+ if (fp == NULL) {
+ (void) fprintf(stderr, MSG_CANNOT_OPEN,
+ whoami, fname, strerror(errno));
+ freestr(line);
+ return (EXIT_CMD_FAILED);
+ }
+
+ (void) fprintf(fp, "%s\n", line->s_str);
+ freestr(line);
+
+ if (fclose(fp) == -1) {
+ (void) fprintf(stderr, MSG_CLOSE_ERROR,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+
+ if (chmod(fname, 0444) == -1) {
+ (void) fprintf(stderr, MSG_CHMOD_ERROR,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ return (EXIT_OK);
+}
+
+
+static int
+list_remove_cmd(int cmd)
+{
+ struct dirent *dp;
+ DIR *dir;
+ char path[MAXPATHLEN+1];
+ char fname[MAXPATHLEN+1];
+ char *suffix;
+ char **dirlist = NULL;
+ int list_size = 0;
+ int list_alloc = 0;
+ char **p;
+ int rval;
+ int result;
+
+ /*
+ * For the remove cmd, at least one of vendor/publisher/class/username
+ * path must be specified. Subclass is only defined within the
+ * context of a class.
+ */
+ if (cmd == CMD_REMOVE) {
+ int noptions = 0;
+ if (arg_vendor)
+ noptions++;
+ if (arg_publisher)
+ noptions++;
+ if (arg_class)
+ noptions++;
+ if (arg_username)
+ noptions++;
+ if (arg_path)
+ noptions++;
+ if (noptions == 0 || (arg_subclass && arg_class == NULL)) {
+ return (usage());
+ }
+ }
+
+ (void) strcpy(path, root_dir);
+ (void) strcat(path, SYSEVENT_CONFIG_DIR);
+
+ if ((dir = opendir(path)) == NULL) {
+ (void) fprintf(stderr, MSG_CANNOT_OPEN_DIR,
+ whoami, path, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+
+ while ((dp = readdir(dir)) != NULL) {
+ if (dp->d_name[0] == '.')
+ continue;
+ if ((strlen(dp->d_name) == 0) ||
+ (strcmp(dp->d_name, "lost+found") == 0))
+ continue;
+ suffix = strrchr(dp->d_name, ',');
+ if (suffix && strcmp(suffix, SYSEVENT_CONF_SUFFIX) == 0) {
+ (void) strcpy(fname, path);
+ (void) strcat(fname, "/");
+ (void) strcat(fname, dp->d_name);
+ dirlist = build_strlist(dirlist,
+ &list_size, &list_alloc, fname);
+ }
+ }
+
+ if (closedir(dir) == -1) {
+ (void) fprintf(stderr, MSG_CLOSE_DIR_ERROR,
+ whoami, path, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+
+ rval = EXIT_NO_MATCH;
+ if (dirlist) {
+ for (p = dirlist; *p != NULL; p++) {
+ switch (cmd) {
+ case CMD_LIST:
+ result = list_file(*p);
+ break;
+ case CMD_REMOVE:
+ result = remove_file(*p);
+ break;
+ }
+ if (rval == EXIT_NO_MATCH &&
+ result != EXIT_NO_MATCH)
+ rval = result;
+ }
+ }
+ return (rval);
+}
+
+
+static int
+list_file(char *fname)
+{
+ FILE *fp;
+ str_t *line;
+ serecord_t *sep;
+ int rval = EXIT_NO_MATCH;
+
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ (void) fprintf(stderr, MSG_CANNOT_OPEN,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ for (;;) {
+ line = read_next_line(fp);
+ if (line == NULL)
+ break;
+ sep = parse_line(line);
+ if (sep != NULL) {
+ if (matches_serecord(sep)) {
+ print_serecord(stdout, sep);
+ rval = EXIT_OK;
+ }
+ free_serecord(sep);
+ }
+ freestr(line);
+ }
+ (void) fclose(fp);
+
+ return (rval);
+}
+
+
+static int
+remove_file(char *fname)
+{
+ FILE *fp;
+ FILE *tmp_fp;
+ str_t *line;
+ char *raw_line;
+ serecord_t *sep;
+ char tmp_name[MAXPATHLEN+1];
+ int is_empty = 1;
+
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ (void) fprintf(stderr, MSG_CANNOT_OPEN,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+
+ if (check_for_removes(fp) == 0) {
+ (void) fclose(fp);
+ return (EXIT_NO_MATCH);
+ }
+
+ rewind(fp);
+
+ (void) strcpy(tmp_name, root_dir);
+ (void) strcat(tmp_name, SYSEVENT_CONFIG_DIR);
+ (void) strcat(tmp_name, "/tmp.XXXXXX");
+ if (mktemp(tmp_name) == NULL) {
+ (void) fprintf(stderr, "unable to make tmp file name\n");
+ return (EXIT_CMD_FAILED);
+ }
+
+ if (creat(tmp_name, 0644) == -1) {
+ (void) fprintf(stderr, MSG_CANNOT_CREATE,
+ whoami, tmp_name, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+
+ tmp_fp = fopen(tmp_name, "a");
+ if (tmp_fp == NULL) {
+ (void) fprintf(stderr, MSG_CANNOT_OPEN,
+ whoami, tmp_name, strerror(errno));
+ (void) unlink(tmp_name);
+ (void) fclose(fp);
+ return (EXIT_CMD_FAILED);
+ }
+
+ for (;;) {
+ line = read_next_line(fp);
+ if (line == NULL)
+ break;
+ raw_line = sc_strdup(line->s_str);
+ sep = parse_line(line);
+ if (sep == NULL) {
+ (void) fputs(line->s_str, tmp_fp);
+ } else {
+ if (!matches_serecord(sep)) {
+ is_empty = 0;
+ (void) fprintf(tmp_fp, "%s\n", raw_line);
+ }
+ free_serecord(sep);
+ }
+ freestr(line);
+ sc_strfree(raw_line);
+ }
+ (void) fclose(fp);
+ if (fclose(tmp_fp) == -1) {
+ (void) fprintf(stderr, MSG_CLOSE_ERROR,
+ whoami, tmp_name, strerror(errno));
+ }
+
+ if (is_empty) {
+ if (unlink(tmp_name) == -1) {
+ (void) fprintf(stderr, MSG_CANNOT_UNLINK,
+ whoami, tmp_name, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ if (unlink(fname) == -1) {
+ (void) fprintf(stderr, MSG_CANNOT_UNLINK,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ } else {
+ if (unlink(fname) == -1) {
+ (void) fprintf(stderr, MSG_CANNOT_UNLINK,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ if (rename(tmp_name, fname) == -1) {
+ (void) fprintf(stderr, MSG_CANNOT_RENAME,
+ whoami, tmp_name, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ if (chmod(fname, 0444) == -1) {
+ (void) fprintf(stderr, MSG_CHMOD_ERROR,
+ whoami, fname, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ }
+
+ return (EXIT_OK);
+}
+
+static int
+check_for_removes(FILE *fp)
+{
+ str_t *line;
+ serecord_t *sep;
+
+ for (;;) {
+ line = read_next_line(fp);
+ if (line == NULL)
+ break;
+ sep = parse_line(line);
+ if (sep != NULL) {
+ if (matches_serecord(sep)) {
+ free_serecord(sep);
+ freestr(line);
+ return (1);
+ }
+ free_serecord(sep);
+ }
+ freestr(line);
+ }
+
+ return (0);
+}
+
+
+static int
+matches_serecord(serecord_t *sep)
+{
+ char *line;
+ char *lp;
+ char *token;
+ int i;
+
+ if (arg_vendor &&
+ strcmp(arg_vendor, sep->se_vendor) != 0) {
+ return (0);
+ }
+
+ if (arg_publisher &&
+ strcmp(arg_publisher, sep->se_publisher) != 0) {
+ return (0);
+ }
+
+ if (arg_class &&
+ strcmp(arg_class, sep->se_class) != 0) {
+ return (0);
+ }
+
+ if (arg_subclass &&
+ strcmp(arg_subclass, sep->se_subclass) != 0) {
+ return (0);
+ }
+
+ if (arg_username &&
+ strcmp(arg_username, sep->se_user) != 0) {
+ return (0);
+ }
+
+ if (arg_path &&
+ strcmp(arg_path, sep->se_path) != 0) {
+ return (0);
+ }
+
+ if (arg_nargs > 0) {
+ line = sc_strdup(sep->se_args);
+ lp = line;
+ for (i = 0; i < arg_nargs; i++) {
+ token = next_field(&lp);
+ if (strcmp(arg_args[i], token) != 0) {
+ sc_strfree(line);
+ return (0);
+ }
+ }
+ sc_strfree(line);
+ }
+
+ return (1);
+}
+
+static void
+print_serecord(FILE *fp, serecord_t *sep)
+{
+ str_t *line;
+
+ line = initstr(128);
+
+ if (strcmp(sep->se_vendor, "-") != 0) {
+ strcats(line, "vendor=");
+ strcats(line, sep->se_vendor);
+ strcats(line, " ");
+ }
+ if (strcmp(sep->se_publisher, "-") != 0) {
+ strcats(line, "publisher=");
+ strcats(line, sep->se_publisher);
+ strcats(line, " ");
+ }
+ if (strcmp(sep->se_class, "-") != 0) {
+ strcats(line, "class=");
+ strcats(line, sep->se_class);
+ strcats(line, " ");
+ if (strcmp(sep->se_subclass, "-") != 0) {
+ strcats(line, "subclass=");
+ strcats(line, sep->se_subclass);
+ strcats(line, " ");
+ }
+ }
+ if (strcmp(sep->se_user, "-") != 0) {
+ strcats(line, "username=");
+ strcats(line, sep->se_user);
+ strcats(line, " ");
+ }
+ strcats(line, sep->se_path);
+ if (sep->se_args) {
+ strcats(line, " ");
+ strcats(line, sep->se_args);
+ }
+ strcats(line, "\n");
+
+ (void) fputs(line->s_str, fp);
+ freestr(line);
+}
+
+
+
+
+static int
+restart_cmd(void)
+{
+ if (system("pkill -HUP syseventd") == -1) {
+ (void) fprintf(stderr, MSG_RESTART_FAILED,
+ whoami, strerror(errno));
+ return (EXIT_CMD_FAILED);
+ }
+ return (EXIT_OK);
+}
+
+
+static str_t *
+read_next_line(FILE *fp)
+{
+ char *lp;
+ str_t *line;
+
+ line = initstr(128);
+
+ lp = fstrgets(line, fp);
+ if (lp == NULL) {
+ freestr(line);
+ return (NULL);
+ }
+
+ *(lp + strlen(lp)-1) = 0;
+ return (line);
+}
+
+
+static serecord_t *
+parse_line(str_t *line)
+{
+ char *lp;
+ char *vendor, *publisher;
+ char *class, *subclass;
+ char *user;
+ char *reserved1, *reserved2;
+ char *path, *args;
+ serecord_t *sep;
+
+ lp = line->s_str;
+ if (*lp == 0 || *lp == '#') {
+ return (NULL);
+ }
+
+ if ((class = next_field(&lp)) != NULL) {
+ subclass = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ vendor = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ publisher = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ user = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ reserved1 = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ reserved2 = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ path = next_field(&lp);
+ if (lp == NULL)
+ return (NULL);
+ args = skip_spaces(&lp);
+ }
+
+ sep = sc_malloc(sizeof (serecord_t));
+
+ sep->se_vendor = sc_strdup(vendor);
+ sep->se_publisher = sc_strdup(publisher);
+ sep->se_class = sc_strdup(class);
+ sep->se_subclass = sc_strdup(subclass);
+ sep->se_user = sc_strdup(user);
+ sep->se_reserved1 = sc_strdup(reserved1);
+ sep->se_reserved2 = sc_strdup(reserved2);
+ sep->se_path = sc_strdup(path);
+ sep->se_args = (args == NULL) ? NULL : sc_strdup(args);
+
+ return (sep);
+}
+
+
+static void
+free_serecord(serecord_t *sep)
+{
+ sc_strfree(sep->se_vendor);
+ sc_strfree(sep->se_publisher);
+ sc_strfree(sep->se_class);
+ sc_strfree(sep->se_subclass);
+ sc_strfree(sep->se_user);
+ sc_strfree(sep->se_reserved1);
+ sc_strfree(sep->se_reserved2);
+ sc_strfree(sep->se_path);
+ sc_strfree(sep->se_args);
+ sc_free(sep, sizeof (serecord_t));
+}
+
+
+/*
+ * skip_spaces() - skip to next non-space character
+ */
+static char *
+skip_spaces(char **cpp)
+{
+ char *cp = *cpp;
+
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == 0) {
+ *cpp = 0;
+ return (NULL);
+ }
+ return (cp);
+}
+
+
+/*
+ * Get next white-space separated field.
+ * next_field() will not check any characters on next line.
+ * Each entry is composed of a single line.
+ */
+static char *
+next_field(char **cpp)
+{
+ char *cp = *cpp;
+ char *start;
+
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == 0) {
+ *cpp = 0;
+ return (NULL);
+ }
+ start = cp;
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ if (*cp != 0)
+ *cp++ = 0;
+ *cpp = cp;
+ return (start);
+}
+
+
+
+/*
+ * The following functions are simple wrappers/equivalents
+ * for malloc, realloc, free, strdup and a special free
+ * for strdup.
+ */
+
+static void *
+sc_malloc(size_t n)
+{
+ void *p;
+
+ p = malloc(n);
+ if (p == NULL) {
+ no_mem_err();
+ }
+ return (p);
+}
+
+/*ARGSUSED*/
+static void *
+sc_realloc(void *p, size_t current, size_t n)
+{
+ p = realloc(p, n);
+ if (p == NULL) {
+ no_mem_err();
+ }
+ return (p);
+}
+
+
+/*ARGSUSED*/
+static void
+sc_free(void *p, size_t n)
+{
+ free(p);
+}
+
+
+static char *
+sc_strdup(char *cp)
+{
+ char *new;
+
+ new = malloc((unsigned)(strlen(cp) + 1));
+ if (new == NULL) {
+ no_mem_err();
+ }
+ (void) strcpy(new, cp);
+ return (new);
+}
+
+
+static void
+sc_strfree(char *s)
+{
+ if (s)
+ free(s);
+}
+
+
+/*
+ * The following functions provide some simple dynamic string
+ * capability. This module has no hard-coded maximum string
+ * lengths and should be able to parse and generate arbitrarily
+ * long strings, macro expansion and command lines.
+ *
+ * Each string must be explicitly allocated and freed.
+ */
+
+/*
+ * Allocate a dynamic string, with a hint to indicate how
+ * much memory to dynamically add to the string as it grows
+ * beyond its existing bounds, so as to avoid excessive
+ * reallocs as a string grows.
+ */
+static str_t *
+initstr(int hint)
+{
+ str_t *str;
+
+ str = sc_malloc(sizeof (str_t));
+ str->s_str = NULL;
+ str->s_len = 0;
+ str->s_alloc = 0;
+ str->s_hint = hint;
+ return (str);
+}
+
+
+/*
+ * Free a dynamically-allocated string
+ */
+static void
+freestr(str_t *str)
+{
+ if (str->s_str) {
+ sc_free(str->s_str, str->s_alloc);
+ }
+ sc_free(str, sizeof (str_t));
+}
+
+
+/*
+ * Reset a dynamically-allocated string, allows reuse
+ * rather than freeing the old and allocating a new one.
+ */
+static void
+resetstr(str_t *str)
+{
+ str->s_len = 0;
+}
+
+
+/*
+ * Concatenate a (simple) string onto a dynamically-allocated string
+ */
+static void
+strcats(str_t *str, char *s)
+{
+ char *new_str;
+ int len = str->s_len + strlen(s) + 1;
+
+ if (str->s_alloc < len) {
+ new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
+ sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
+ str->s_str = new_str;
+ str->s_alloc = len + str->s_hint;
+ }
+ (void) strcpy(str->s_str + str->s_len, s);
+ str->s_len = len - 1;
+}
+
+
+/*
+ * Concatenate a character onto a dynamically-allocated string
+ */
+static void
+strcatc(str_t *str, int c)
+{
+ char *new_str;
+ int len = str->s_len + 2;
+
+ if (str->s_alloc < len) {
+ new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
+ sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
+ str->s_str = new_str;
+ str->s_alloc = len + str->s_hint;
+ }
+ *(str->s_str + str->s_len) = (char)c;
+ *(str->s_str + str->s_len + 1) = 0;
+ str->s_len++;
+}
+
+/*
+ * fgets() equivalent using a dynamically-allocated string
+ */
+static char *
+fstrgets(str_t *line, FILE *fp)
+{
+ int c;
+
+ resetstr(line);
+ while ((c = fgetc(fp)) != EOF) {
+ strcatc(line, c);
+ if (c == '\n')
+ break;
+ }
+ if (line->s_len == 0)
+ return (NULL);
+ return (line->s_str);
+}
+
+
+
+#define INITIAL_LISTSIZE 4
+#define INCR_LISTSIZE 4
+
+static char **
+build_strlist(
+ char **argvlist,
+ int *size,
+ int *alloc,
+ char *str)
+{
+ int n;
+
+ if (*size + 1 > *alloc) {
+ if (*alloc == 0) {
+ *alloc = INITIAL_LISTSIZE;
+ n = sizeof (char *) * (*alloc + 1);
+ argvlist = (char **)malloc(n);
+ if (argvlist == NULL)
+ no_mem_err();
+ } else {
+ *alloc += INCR_LISTSIZE;
+ n = sizeof (char *) * (*alloc + 1);
+ argvlist = (char **)realloc(argvlist, n);
+ if (argvlist == NULL)
+ no_mem_err();
+ }
+ }
+
+ argvlist[*size] = strdup(str);
+ *size += 1;
+ argvlist[*size] = NULL;
+
+ return (argvlist);
+}
+
+static void
+no_mem_err()
+{
+ (void) fprintf(stderr, MSG_NO_MEM, whoami);
+ exit_lock();
+ exit(EXIT_NO_MEM);
+ /*NOTREACHED*/
+}
diff --git a/usr/src/cmd/syseventadm/syseventadm.h b/usr/src/cmd/syseventadm/syseventadm.h
new file mode 100644
index 0000000000..0fb39f9d70
--- /dev/null
+++ b/usr/src/cmd/syseventadm/syseventadm.h
@@ -0,0 +1,138 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYSEVENTADM_H
+#define _SYSEVENTADM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Directory where sysevent.conf files reside
+ */
+#define SYSEVENT_CONFIG_DIR "/etc/sysevent/config"
+
+/*
+ * Lock file name to serialize registry updates
+ */
+#define LOCK_FILENAME "sysevent.lock"
+
+/*
+ * Required suffix for all sysevent.conf files
+ */
+#define SYSEVENT_CONF_SUFFIX ",sysevent.conf"
+
+/*
+ * cmd types for list/remove
+ */
+#define CMD_LIST 0
+#define CMD_REMOVE 1
+
+/*
+ * Exit codes
+ */
+#define EXIT_OK 0
+#define EXIT_NO_MATCH 1
+#define EXIT_USAGE 2
+#define EXIT_PERM 3
+#define EXIT_CMD_FAILED 4
+#define EXIT_NO_MEM 5
+
+/*
+ * sysevent.conf record
+ */
+typedef struct serecord {
+ char *se_vendor; /* vendor */
+ char *se_publisher; /* publisher */
+ char *se_class; /* event class */
+ char *se_subclass; /* event subclass */
+ char *se_user; /* user */
+ char *se_reserved1; /* reserved1 */
+ char *se_reserved2; /* reserved2 */
+ char *se_path; /* event path */
+ char *se_args; /* optional args */
+} serecord_t;
+
+
+/*
+ * Structures for building arbitarily long strings and argument lists
+ */
+typedef struct str {
+ char *s_str;
+ int s_len;
+ int s_alloc;
+ int s_hint;
+} str_t;
+
+
+/*
+ * Prototypes
+ */
+int main(int argc, char **argv);
+static void enter_lock(char *root_dir);
+static void exit_lock(void);
+static void set_root_dir(char *dir);
+static int usage(void);
+static int add_cmd(void);
+static int list_remove_cmd(int cmd);
+static int list_file(char *fname);
+static int remove_file(char *fname);
+static int check_for_removes(FILE *fp);
+static int restart_cmd(void);
+
+static str_t *read_next_line(FILE *fp);
+static serecord_t *parse_line(str_t *line);
+
+static int matches_serecord(serecord_t *sep);
+static void print_serecord(FILE *fp, serecord_t *sep);
+static void free_serecord(serecord_t *sep);
+
+static char *skip_spaces(char **cpp);
+static char *next_field(char **cpp);
+static void *sc_malloc(size_t n);
+static void *sc_realloc(void *p, size_t current, size_t n);
+static void sc_free(void *p, size_t n);
+static char *sc_strdup(char *cp);
+static void sc_strfree(char *s);
+
+static str_t *initstr(int hint);
+static void freestr(str_t *str);
+static void resetstr(str_t *str);
+static void strcats(str_t *str, char *s);
+static void strcatc(str_t *str, int c);
+static char *fstrgets(str_t *str, FILE *fp);
+static char **build_strlist(char **, int *, int *, char *);
+
+static void no_mem_err(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYSEVENTADM_H */
diff --git a/usr/src/cmd/syseventadm/syseventadm_msg.h b/usr/src/cmd/syseventadm/syseventadm_msg.h
new file mode 100644
index 0000000000..c2e1b2e4bf
--- /dev/null
+++ b/usr/src/cmd/syseventadm/syseventadm_msg.h
@@ -0,0 +1,103 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYSEVENTADM_MSG_H
+#define _SYSEVENTADM_MSG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Gettext strings for internationalization
+ */
+#define MSG_NOT_ROOT \
+ gettext("%s: must be root\n")
+
+#define MSG_NOT_GLOBAL \
+ gettext("%s: must be in global zone\n")
+
+#define MSG_CANNOT_CREATE \
+ gettext("%s: cannot create %s - %s\n")
+
+#define MSG_CANNOT_OPEN \
+ gettext("%s: cannot open %s - %s\n")
+
+#define MSG_CLOSE_ERROR \
+ gettext("%s: close of %s failed - %s\n")
+
+#define MSG_CHMOD_ERROR \
+ gettext("%s: cannot chmod %s to 0444 - %s\n")
+
+#define MSG_CANNOT_OPEN_DIR \
+ gettext("%s: cannot open directory %s - %s\n")
+
+#define MSG_CLOSE_DIR_ERROR \
+ gettext("%s: close of directory %s failed - %s\n")
+
+#define MSG_TMP_FILE \
+ gettext("%s: unable to make tmp file name\n")
+
+#define MSG_CANNOT_UNLINK \
+ gettext("%s: cannot unlink %s - %s\n")
+
+#define MSG_CANNOT_RENAME \
+ gettext("%s: cannot rename %s to %s - %s\n")
+
+#define MSG_RESTART_FAILED \
+ gettext("%s: restart failed - %s\n")
+
+#define MSG_NO_MEM \
+ gettext("%s: out of memory\n")
+
+#define MSG_USAGE_INTRO \
+ gettext("usage: syseventadm <cmd> ...\n")
+
+#define MSG_USAGE_OPTIONS \
+ gettext("where the possible commands and options for each are:\n")
+
+#define MSG_LOCK_CREATE_ERR \
+ gettext("%s: error creating lock %s - %s\n")
+
+#define MSG_LOCK_PATH_ERR \
+ gettext("%s: error creating lock %s - file path invalid\n")
+
+#define MSG_LOCK_SET_ERR \
+ gettext("%s: error setting lock in %s - %s\n")
+
+#define MSG_LOCK_CLR_ERR \
+ gettext("%s: error clearing lock in %s - %s\n")
+
+#define MSG_LOCK_CLOSE_ERR \
+ gettext("%s: error closing lock %s - %s\n")
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYSEVENTADM_MSG_H */