17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*c6fc6dddSEric Schrock  * Common Development and Distribution License (the "License").
6*c6fc6dddSEric Schrock  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*c6fc6dddSEric Schrock  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  *	syseventadm - command to administer the sysevent.conf registry
287c478bd9Sstevel@tonic-gate  *		    - administers the general purpose event framework
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  *	The current implementation of the registry using files in
317c478bd9Sstevel@tonic-gate  *	/etc/sysevent/config, files are named as event specifications
327c478bd9Sstevel@tonic-gate  *	are added with the combination of the vendor, publisher, event
337c478bd9Sstevel@tonic-gate  *	class and subclass strings:
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  *	[<vendor>,][<publisher>,][<class>,]sysevent.conf
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <ctype.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate #include <dirent.h>
427c478bd9Sstevel@tonic-gate #include <stdarg.h>
437c478bd9Sstevel@tonic-gate #include <stddef.h>
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <dlfcn.h>
467c478bd9Sstevel@tonic-gate #include <door.h>
477c478bd9Sstevel@tonic-gate #include <errno.h>
487c478bd9Sstevel@tonic-gate #include <fcntl.h>
497c478bd9Sstevel@tonic-gate #include <signal.h>
507c478bd9Sstevel@tonic-gate #include <strings.h>
517c478bd9Sstevel@tonic-gate #include <unistd.h>
527c478bd9Sstevel@tonic-gate #include <synch.h>
537c478bd9Sstevel@tonic-gate #include <syslog.h>
547c478bd9Sstevel@tonic-gate #include <thread.h>
557c478bd9Sstevel@tonic-gate #include <limits.h>
567c478bd9Sstevel@tonic-gate #include <locale.h>
577c478bd9Sstevel@tonic-gate #include <assert.h>
587c478bd9Sstevel@tonic-gate #include <libsysevent.h>
597c478bd9Sstevel@tonic-gate #include <zone.h>
607c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
617c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
627c478bd9Sstevel@tonic-gate #include <sys/param.h>
637c478bd9Sstevel@tonic-gate #include <sys/stat.h>
647c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
657c478bd9Sstevel@tonic-gate #include <sys/wait.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #include "syseventadm.h"
687c478bd9Sstevel@tonic-gate #include "syseventadm_msg.h"
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #ifndef DEBUG
717c478bd9Sstevel@tonic-gate #undef	assert
727c478bd9Sstevel@tonic-gate #define	assert(EX) ((void)0)
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static char	*whoami		= NULL;
767c478bd9Sstevel@tonic-gate static char	*root_dir	= "";
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static char	*arg_vendor	= NULL;
797c478bd9Sstevel@tonic-gate static char	*arg_publisher	= NULL;
807c478bd9Sstevel@tonic-gate static char	*arg_class	= NULL;
817c478bd9Sstevel@tonic-gate static char	*arg_subclass	= NULL;
827c478bd9Sstevel@tonic-gate static char	*arg_username	= NULL;
837c478bd9Sstevel@tonic-gate static char	*arg_path	= NULL;
847c478bd9Sstevel@tonic-gate static int	arg_nargs	= 0;
857c478bd9Sstevel@tonic-gate static char	**arg_args	= NULL;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static	int	lock_fd;
887c478bd9Sstevel@tonic-gate static	char 	lock_file[PATH_MAX + 1];
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate extern char	*optarg;
917c478bd9Sstevel@tonic-gate extern int	optind;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static int
usage_gen()947c478bd9Sstevel@tonic-gate usage_gen()
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_USAGE_INTRO);
977c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_USAGE_OPTIONS);
987c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n"
997c478bd9Sstevel@tonic-gate 	    "\tsyseventadm add ...\n"
1007c478bd9Sstevel@tonic-gate 	    "\tsyseventadm remove ...\n"
1017c478bd9Sstevel@tonic-gate 	    "\tsyseventadm list ...\n"
1027c478bd9Sstevel@tonic-gate 	    "\tsyseventadm restart\n"
1037c478bd9Sstevel@tonic-gate 	    "\tsyseventadm help\n");
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	return (EXIT_USAGE);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static int
serve_syseventdotconf(int argc,char ** argv,char * cmd)1097c478bd9Sstevel@tonic-gate serve_syseventdotconf(int argc, char **argv, char *cmd)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	int	c;
1127c478bd9Sstevel@tonic-gate 	int	rval;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "R:v:p:c:s:u:")) != EOF) {
1157c478bd9Sstevel@tonic-gate 		switch (c) {
1167c478bd9Sstevel@tonic-gate 		case 'R':
1177c478bd9Sstevel@tonic-gate 			/*
1187c478bd9Sstevel@tonic-gate 			 * Alternate root path for install, etc.
1197c478bd9Sstevel@tonic-gate 			 */
1207c478bd9Sstevel@tonic-gate 			set_root_dir(optarg);
1217c478bd9Sstevel@tonic-gate 			break;
1227c478bd9Sstevel@tonic-gate 		case 'v':
1237c478bd9Sstevel@tonic-gate 			arg_vendor = optarg;
1247c478bd9Sstevel@tonic-gate 			break;
1257c478bd9Sstevel@tonic-gate 		case 'p':
1267c478bd9Sstevel@tonic-gate 			arg_publisher = optarg;
1277c478bd9Sstevel@tonic-gate 			break;
1287c478bd9Sstevel@tonic-gate 		case 'c':
1297c478bd9Sstevel@tonic-gate 			arg_class = optarg;
1307c478bd9Sstevel@tonic-gate 			break;
1317c478bd9Sstevel@tonic-gate 		case 's':
1327c478bd9Sstevel@tonic-gate 			arg_subclass = optarg;
1337c478bd9Sstevel@tonic-gate 			break;
1347c478bd9Sstevel@tonic-gate 		case 'u':
1357c478bd9Sstevel@tonic-gate 			arg_username = optarg;
1367c478bd9Sstevel@tonic-gate 			break;
1377c478bd9Sstevel@tonic-gate 		default:
1387c478bd9Sstevel@tonic-gate 			return (usage());
1397c478bd9Sstevel@tonic-gate 		}
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (optind < argc) {
1437c478bd9Sstevel@tonic-gate 		arg_path = argv[optind++];
1447c478bd9Sstevel@tonic-gate 		if (optind < argc) {
1457c478bd9Sstevel@tonic-gate 			arg_nargs = argc - optind;
1467c478bd9Sstevel@tonic-gate 			arg_args = argv + optind;
1477c478bd9Sstevel@tonic-gate 		}
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	enter_lock(root_dir);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "add") == 0) {
1537c478bd9Sstevel@tonic-gate 		rval = add_cmd();
1547c478bd9Sstevel@tonic-gate 	} else if (strcmp(cmd, "list") == 0) {
1557c478bd9Sstevel@tonic-gate 		rval = list_remove_cmd(CMD_LIST);
1567c478bd9Sstevel@tonic-gate 	} else if (strcmp(cmd, "remove") == 0) {
1577c478bd9Sstevel@tonic-gate 		rval = list_remove_cmd(CMD_REMOVE);
1587c478bd9Sstevel@tonic-gate 	} else if (strcmp(cmd, "restart") == 0) {
1597c478bd9Sstevel@tonic-gate 		rval = restart_cmd();
1607c478bd9Sstevel@tonic-gate 	} else {
1617c478bd9Sstevel@tonic-gate 		rval = usage();
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	exit_lock();
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	return (rval);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1717c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	char	*cmd;
1747c478bd9Sstevel@tonic-gate 	int	rval;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1787c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if ((whoami = strrchr(argv[0], '/')) == NULL) {
1817c478bd9Sstevel@tonic-gate 		whoami = argv[0];
1827c478bd9Sstevel@tonic-gate 	} else {
1837c478bd9Sstevel@tonic-gate 		whoami++;
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (argc == 1) {
1877c478bd9Sstevel@tonic-gate 		return (usage_gen());
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	cmd = argv[optind++];
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* Allow non-privileged users to get the help messages */
1937c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "help") == 0) {
1947c478bd9Sstevel@tonic-gate 		rval = usage_gen();
1957c478bd9Sstevel@tonic-gate 		return (rval);
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
1997c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_NOT_ROOT, whoami);
2007c478bd9Sstevel@tonic-gate 		exit(EXIT_PERM);
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "evc") != 0 && getzoneid() != GLOBAL_ZONEID) {
2047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_NOT_GLOBAL, whoami);
2057c478bd9Sstevel@tonic-gate 		exit(EXIT_PERM);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "add") == 0 ||
2097c478bd9Sstevel@tonic-gate 	    strcmp(cmd, "remove") == 0 || strcmp(cmd, "list") == 0 ||
2107c478bd9Sstevel@tonic-gate 	    strcmp(cmd, "restart") == 0) {
2117c478bd9Sstevel@tonic-gate 		rval = serve_syseventdotconf(argc, argv, cmd);
2127c478bd9Sstevel@tonic-gate 	} else {
2137c478bd9Sstevel@tonic-gate 		rval = usage_gen();
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	return (rval);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate static void
enter_lock(char * root_dir)2207c478bd9Sstevel@tonic-gate enter_lock(char *root_dir)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	struct flock	lock;
2237c478bd9Sstevel@tonic-gate 
224*c6fc6dddSEric Schrock 	if (snprintf(lock_file, sizeof (lock_file), "%s%s", root_dir,
225*c6fc6dddSEric Schrock 	    LOCK_FILENAME) >= sizeof (lock_file)) {
2267c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_PATH_ERR, whoami, lock_file);
2277c478bd9Sstevel@tonic-gate 		exit(EXIT_CMD_FAILED);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 	lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
2307c478bd9Sstevel@tonic-gate 	if (lock_fd < 0) {
2317c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_CREATE_ERR,
2327c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
2337c478bd9Sstevel@tonic-gate 		exit(EXIT_CMD_FAILED);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
2377c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
2387c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
2397c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate retry:
2427c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
2437c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR)
2447c478bd9Sstevel@tonic-gate 			goto retry;
2457c478bd9Sstevel@tonic-gate 		(void) close(lock_fd);
2467c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_SET_ERR,
2477c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
2487c478bd9Sstevel@tonic-gate 		exit(EXIT_CMD_FAILED);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate static void
exit_lock()2547c478bd9Sstevel@tonic-gate exit_lock()
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	struct flock	lock;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
2597c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
2607c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
2617c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLK, &lock) == -1) {
2647c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_CLR_ERR,
2657c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (close(lock_fd) == -1) {
2697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_CLOSE_ERR,
2707c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate static void
set_root_dir(char * dir)2767c478bd9Sstevel@tonic-gate set_root_dir(char *dir)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	root_dir = sc_strdup(dir);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate static char *usage_msg[] = {
2837c478bd9Sstevel@tonic-gate 	"\n"
2847c478bd9Sstevel@tonic-gate 	"\tsyseventadm add [-R <rootdir>] [-v vendor] [-p publisher]\n"
2857c478bd9Sstevel@tonic-gate 	"\t[-c class] [-s subclass] [-u username] path [args]\n"
2867c478bd9Sstevel@tonic-gate 	"\n"
2877c478bd9Sstevel@tonic-gate 	"\tsyseventadm remove [-R <rootdir>] [-v vendor] [-p publisher]\n"
2887c478bd9Sstevel@tonic-gate 	"\t[-c class] [-s subclass] [-u username] [path [args]]\n"
2897c478bd9Sstevel@tonic-gate 	"\n"
2907c478bd9Sstevel@tonic-gate 	"\tsyseventadm list [-R <rootdir>] [-v vendor] [-p publisher]\n"
2917c478bd9Sstevel@tonic-gate 	"\t[-c class] [-s subclass] [-u username] [path [args]]\n"
2927c478bd9Sstevel@tonic-gate };
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate static int
usage()2957c478bd9Sstevel@tonic-gate usage()
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	char	**msgs;
2987c478bd9Sstevel@tonic-gate 	int	i;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	msgs = usage_msg;
3017c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (usage_msg)/sizeof (char *); i++) {
3027c478bd9Sstevel@tonic-gate 		(void) fputs(*msgs++, stderr);
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	return (EXIT_USAGE);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static int
add_cmd(void)3107c478bd9Sstevel@tonic-gate add_cmd(void)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	char	fname[MAXPATHLEN+1];
3137c478bd9Sstevel@tonic-gate 	int	need_comma = 0;
3147c478bd9Sstevel@tonic-gate 	int	noptions = 0;
3157c478bd9Sstevel@tonic-gate 	struct stat st;
3167c478bd9Sstevel@tonic-gate 	FILE	*fp;
3177c478bd9Sstevel@tonic-gate 	str_t	*line;
3187c478bd9Sstevel@tonic-gate 	int	i;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * At least one of vendor/publisher/class must be specified.
3227c478bd9Sstevel@tonic-gate 	 * Subclass is only defined within the context of class.
3237c478bd9Sstevel@tonic-gate 	 * For add, path must also be specified.
3247c478bd9Sstevel@tonic-gate 	 */
3257c478bd9Sstevel@tonic-gate 	if (arg_vendor)
3267c478bd9Sstevel@tonic-gate 		noptions++;
3277c478bd9Sstevel@tonic-gate 	if (arg_publisher)
3287c478bd9Sstevel@tonic-gate 		noptions++;
3297c478bd9Sstevel@tonic-gate 	if (arg_class)
3307c478bd9Sstevel@tonic-gate 		noptions++;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (noptions == 0 || (arg_subclass && arg_class == NULL)) {
3337c478bd9Sstevel@tonic-gate 		return (usage());
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (arg_path == NULL)
3377c478bd9Sstevel@tonic-gate 		return (usage());
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * Generate the sysevent.conf file name
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, root_dir);
3437c478bd9Sstevel@tonic-gate 	(void) strcat(fname, SYSEVENT_CONFIG_DIR);
3447c478bd9Sstevel@tonic-gate 	(void) strcat(fname, "/");
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (arg_vendor) {
3477c478bd9Sstevel@tonic-gate 		(void) strcat(fname, arg_vendor);
3487c478bd9Sstevel@tonic-gate 		need_comma = 1;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	if (arg_publisher) {
3517c478bd9Sstevel@tonic-gate 		if (need_comma)
3527c478bd9Sstevel@tonic-gate 			(void) strcat(fname, ",");
3537c478bd9Sstevel@tonic-gate 		(void) strcat(fname, arg_publisher);
3547c478bd9Sstevel@tonic-gate 		need_comma = 1;
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	if (arg_class) {
3577c478bd9Sstevel@tonic-gate 		if (need_comma)
3587c478bd9Sstevel@tonic-gate 			(void) strcat(fname, ",");
3597c478bd9Sstevel@tonic-gate 		(void) strcat(fname, arg_class);
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 	(void) strcat(fname, SYSEVENT_CONF_SUFFIX);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/*
3647c478bd9Sstevel@tonic-gate 	 * Prepare the line to be written to the sysevent.conf file
3657c478bd9Sstevel@tonic-gate 	 */
3667c478bd9Sstevel@tonic-gate 	line = initstr(128);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	strcats(line, arg_class == NULL ? "-" : arg_class);
3697c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	strcats(line, arg_subclass == NULL ? "-" : arg_subclass);
3727c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	strcats(line, arg_vendor == NULL ? "-" : arg_vendor);
3757c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	strcats(line, arg_publisher == NULL ? "-" : arg_publisher);
3787c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	strcats(line, arg_username == NULL ? "-" : arg_username);
3817c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	strcats(line, "- - ");
3847c478bd9Sstevel@tonic-gate 	strcats(line, arg_path);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	if (arg_nargs) {
3877c478bd9Sstevel@tonic-gate 		for (i = 0; i < arg_nargs; i++) {
3887c478bd9Sstevel@tonic-gate 			strcatc(line, ' ');
3897c478bd9Sstevel@tonic-gate 			strcats(line, arg_args[i]);
3907c478bd9Sstevel@tonic-gate 		}
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if (stat(fname, &st) == -1) {
3947c478bd9Sstevel@tonic-gate 		if (creat(fname, 0644) == -1) {
3957c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_CREATE,
3967c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
3977c478bd9Sstevel@tonic-gate 			freestr(line);
3987c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
3997c478bd9Sstevel@tonic-gate 		}
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "a");
4037c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
4047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
4057c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
4067c478bd9Sstevel@tonic-gate 		freestr(line);
4077c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%s\n", line->s_str);
4117c478bd9Sstevel@tonic-gate 	freestr(line);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (fclose(fp) == -1) {
4147c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CLOSE_ERROR,
4157c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
4167c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (chmod(fname, 0444) == -1) {
4207c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CHMOD_ERROR,
4217c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
4227c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 	return (EXIT_OK);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate static int
list_remove_cmd(int cmd)4297c478bd9Sstevel@tonic-gate list_remove_cmd(int cmd)
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
4327c478bd9Sstevel@tonic-gate 	DIR		*dir;
4337c478bd9Sstevel@tonic-gate 	char		path[MAXPATHLEN+1];
4347c478bd9Sstevel@tonic-gate 	char		fname[MAXPATHLEN+1];
4357c478bd9Sstevel@tonic-gate 	char		*suffix;
4367c478bd9Sstevel@tonic-gate 	char		**dirlist = NULL;
4377c478bd9Sstevel@tonic-gate 	int		list_size = 0;
4387c478bd9Sstevel@tonic-gate 	int		list_alloc = 0;
4397c478bd9Sstevel@tonic-gate 	char		**p;
4407c478bd9Sstevel@tonic-gate 	int		rval;
4417c478bd9Sstevel@tonic-gate 	int		result;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/*
4447c478bd9Sstevel@tonic-gate 	 * For the remove cmd, at least one of vendor/publisher/class/username
4457c478bd9Sstevel@tonic-gate 	 * path must be specified.  Subclass is only defined within the
4467c478bd9Sstevel@tonic-gate 	 * context of a class.
4477c478bd9Sstevel@tonic-gate 	 */
4487c478bd9Sstevel@tonic-gate 	if (cmd == CMD_REMOVE) {
4497c478bd9Sstevel@tonic-gate 		int	noptions = 0;
4507c478bd9Sstevel@tonic-gate 		if (arg_vendor)
4517c478bd9Sstevel@tonic-gate 			noptions++;
4527c478bd9Sstevel@tonic-gate 		if (arg_publisher)
4537c478bd9Sstevel@tonic-gate 			noptions++;
4547c478bd9Sstevel@tonic-gate 		if (arg_class)
4557c478bd9Sstevel@tonic-gate 			noptions++;
4567c478bd9Sstevel@tonic-gate 		if (arg_username)
4577c478bd9Sstevel@tonic-gate 			noptions++;
4587c478bd9Sstevel@tonic-gate 		if (arg_path)
4597c478bd9Sstevel@tonic-gate 			noptions++;
4607c478bd9Sstevel@tonic-gate 		if (noptions == 0 || (arg_subclass && arg_class == NULL)) {
4617c478bd9Sstevel@tonic-gate 			return (usage());
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	(void) strcpy(path, root_dir);
4667c478bd9Sstevel@tonic-gate 	(void) strcat(path, SYSEVENT_CONFIG_DIR);
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	if ((dir = opendir(path)) == NULL) {
4697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN_DIR,
4707c478bd9Sstevel@tonic-gate 			whoami, path, strerror(errno));
4717c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
4757c478bd9Sstevel@tonic-gate 		if (dp->d_name[0] == '.')
4767c478bd9Sstevel@tonic-gate 			continue;
4777c478bd9Sstevel@tonic-gate 		if ((strlen(dp->d_name) == 0) ||
4787c478bd9Sstevel@tonic-gate 		    (strcmp(dp->d_name, "lost+found") == 0))
4797c478bd9Sstevel@tonic-gate 			continue;
4807c478bd9Sstevel@tonic-gate 		suffix = strrchr(dp->d_name, ',');
4817c478bd9Sstevel@tonic-gate 		if (suffix && strcmp(suffix, SYSEVENT_CONF_SUFFIX) == 0) {
4827c478bd9Sstevel@tonic-gate 			(void) strcpy(fname, path);
4837c478bd9Sstevel@tonic-gate 			(void) strcat(fname, "/");
4847c478bd9Sstevel@tonic-gate 			(void) strcat(fname, dp->d_name);
4857c478bd9Sstevel@tonic-gate 			dirlist = build_strlist(dirlist,
4867c478bd9Sstevel@tonic-gate 				&list_size, &list_alloc, fname);
4877c478bd9Sstevel@tonic-gate 		}
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (closedir(dir) == -1) {
4917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CLOSE_DIR_ERROR,
4927c478bd9Sstevel@tonic-gate 			whoami, path, strerror(errno));
4937c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	rval = EXIT_NO_MATCH;
4977c478bd9Sstevel@tonic-gate 	if (dirlist) {
4987c478bd9Sstevel@tonic-gate 		for (p = dirlist; *p != NULL; p++) {
4997c478bd9Sstevel@tonic-gate 			switch (cmd) {
5007c478bd9Sstevel@tonic-gate 			case CMD_LIST:
5017c478bd9Sstevel@tonic-gate 				result = list_file(*p);
5027c478bd9Sstevel@tonic-gate 				break;
5037c478bd9Sstevel@tonic-gate 			case CMD_REMOVE:
5047c478bd9Sstevel@tonic-gate 				result = remove_file(*p);
5057c478bd9Sstevel@tonic-gate 				break;
5067c478bd9Sstevel@tonic-gate 			}
5077c478bd9Sstevel@tonic-gate 			if (rval == EXIT_NO_MATCH &&
5087c478bd9Sstevel@tonic-gate 			    result != EXIT_NO_MATCH)
5097c478bd9Sstevel@tonic-gate 				rval = result;
5107c478bd9Sstevel@tonic-gate 		}
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 	return (rval);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate static int
list_file(char * fname)5177c478bd9Sstevel@tonic-gate list_file(char *fname)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	FILE		*fp;
5207c478bd9Sstevel@tonic-gate 	str_t		*line;
5217c478bd9Sstevel@tonic-gate 	serecord_t	*sep;
5227c478bd9Sstevel@tonic-gate 	int		rval = EXIT_NO_MATCH;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "r");
5257c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
5267c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
5277c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
5287c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 	for (;;) {
5317c478bd9Sstevel@tonic-gate 		line = read_next_line(fp);
5327c478bd9Sstevel@tonic-gate 		if (line == NULL)
5337c478bd9Sstevel@tonic-gate 			break;
5347c478bd9Sstevel@tonic-gate 		sep = parse_line(line);
5357c478bd9Sstevel@tonic-gate 		if (sep != NULL) {
5367c478bd9Sstevel@tonic-gate 			if (matches_serecord(sep)) {
5377c478bd9Sstevel@tonic-gate 				print_serecord(stdout, sep);
5387c478bd9Sstevel@tonic-gate 				rval = EXIT_OK;
5397c478bd9Sstevel@tonic-gate 			}
5407c478bd9Sstevel@tonic-gate 			free_serecord(sep);
5417c478bd9Sstevel@tonic-gate 		}
5427c478bd9Sstevel@tonic-gate 		freestr(line);
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	return (rval);
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate static int
remove_file(char * fname)5517c478bd9Sstevel@tonic-gate remove_file(char *fname)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	FILE		*fp;
5547c478bd9Sstevel@tonic-gate 	FILE		*tmp_fp;
5557c478bd9Sstevel@tonic-gate 	str_t		*line;
5567c478bd9Sstevel@tonic-gate 	char		*raw_line;
5577c478bd9Sstevel@tonic-gate 	serecord_t	*sep;
5587c478bd9Sstevel@tonic-gate 	char		tmp_name[MAXPATHLEN+1];
5597c478bd9Sstevel@tonic-gate 	int		is_empty = 1;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "r");
5627c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
5637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
5647c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
5657c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	if (check_for_removes(fp) == 0) {
5697c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
5707c478bd9Sstevel@tonic-gate 		return (EXIT_NO_MATCH);
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	rewind(fp);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	(void) strcpy(tmp_name, root_dir);
5767c478bd9Sstevel@tonic-gate 	(void) strcat(tmp_name, SYSEVENT_CONFIG_DIR);
5777c478bd9Sstevel@tonic-gate 	(void) strcat(tmp_name, "/tmp.XXXXXX");
5787c478bd9Sstevel@tonic-gate 	if (mktemp(tmp_name) == NULL) {
5797c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "unable to make tmp file name\n");
5807c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if (creat(tmp_name, 0644) == -1) {
5847c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_CREATE,
5857c478bd9Sstevel@tonic-gate 			whoami, tmp_name, strerror(errno));
5867c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	tmp_fp = fopen(tmp_name, "a");
5907c478bd9Sstevel@tonic-gate 	if (tmp_fp == NULL) {
5917c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
5927c478bd9Sstevel@tonic-gate 			whoami, tmp_name, strerror(errno));
5937c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_name);
5947c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
5957c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	for (;;) {
5997c478bd9Sstevel@tonic-gate 		line = read_next_line(fp);
6007c478bd9Sstevel@tonic-gate 		if (line == NULL)
6017c478bd9Sstevel@tonic-gate 			break;
6027c478bd9Sstevel@tonic-gate 		raw_line = sc_strdup(line->s_str);
6037c478bd9Sstevel@tonic-gate 		sep = parse_line(line);
6047c478bd9Sstevel@tonic-gate 		if (sep == NULL) {
6057c478bd9Sstevel@tonic-gate 			(void) fputs(line->s_str, tmp_fp);
6067c478bd9Sstevel@tonic-gate 		} else {
6077c478bd9Sstevel@tonic-gate 			if (!matches_serecord(sep)) {
6087c478bd9Sstevel@tonic-gate 				is_empty = 0;
6097c478bd9Sstevel@tonic-gate 				(void) fprintf(tmp_fp, "%s\n", raw_line);
6107c478bd9Sstevel@tonic-gate 			}
6117c478bd9Sstevel@tonic-gate 			free_serecord(sep);
6127c478bd9Sstevel@tonic-gate 		}
6137c478bd9Sstevel@tonic-gate 		freestr(line);
6147c478bd9Sstevel@tonic-gate 		sc_strfree(raw_line);
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
6177c478bd9Sstevel@tonic-gate 	if (fclose(tmp_fp) == -1) {
6187c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CLOSE_ERROR,
6197c478bd9Sstevel@tonic-gate 			whoami, tmp_name, strerror(errno));
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (is_empty) {
6237c478bd9Sstevel@tonic-gate 		if (unlink(tmp_name) == -1) {
6247c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_UNLINK,
6257c478bd9Sstevel@tonic-gate 				whoami, tmp_name, strerror(errno));
6267c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
6277c478bd9Sstevel@tonic-gate 		}
6287c478bd9Sstevel@tonic-gate 		if (unlink(fname) == -1) {
6297c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_UNLINK,
6307c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
6317c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 	} else {
6347c478bd9Sstevel@tonic-gate 		if (unlink(fname) == -1) {
6357c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_UNLINK,
6367c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
6377c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 		if (rename(tmp_name, fname) == -1) {
6407c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_RENAME,
6417c478bd9Sstevel@tonic-gate 				whoami, tmp_name, fname, strerror(errno));
6427c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
6437c478bd9Sstevel@tonic-gate 		}
6447c478bd9Sstevel@tonic-gate 		if (chmod(fname, 0444) == -1) {
6457c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CHMOD_ERROR,
6467c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
6477c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	return (EXIT_OK);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate static int
check_for_removes(FILE * fp)6557c478bd9Sstevel@tonic-gate check_for_removes(FILE *fp)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate 	str_t		*line;
6587c478bd9Sstevel@tonic-gate 	serecord_t	*sep;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	for (;;) {
6617c478bd9Sstevel@tonic-gate 		line = read_next_line(fp);
6627c478bd9Sstevel@tonic-gate 		if (line == NULL)
6637c478bd9Sstevel@tonic-gate 			break;
6647c478bd9Sstevel@tonic-gate 		sep = parse_line(line);
6657c478bd9Sstevel@tonic-gate 		if (sep != NULL) {
6667c478bd9Sstevel@tonic-gate 			if (matches_serecord(sep)) {
6677c478bd9Sstevel@tonic-gate 				free_serecord(sep);
6687c478bd9Sstevel@tonic-gate 				freestr(line);
6697c478bd9Sstevel@tonic-gate 				return (1);
6707c478bd9Sstevel@tonic-gate 			}
6717c478bd9Sstevel@tonic-gate 			free_serecord(sep);
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 		freestr(line);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	return (0);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate static int
matches_serecord(serecord_t * sep)6817c478bd9Sstevel@tonic-gate matches_serecord(serecord_t *sep)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate 	char	*line;
6847c478bd9Sstevel@tonic-gate 	char	*lp;
6857c478bd9Sstevel@tonic-gate 	char	*token;
6867c478bd9Sstevel@tonic-gate 	int	i;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	if (arg_vendor &&
6897c478bd9Sstevel@tonic-gate 	    strcmp(arg_vendor, sep->se_vendor) != 0) {
6907c478bd9Sstevel@tonic-gate 		return (0);
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	if (arg_publisher &&
6947c478bd9Sstevel@tonic-gate 	    strcmp(arg_publisher, sep->se_publisher) != 0) {
6957c478bd9Sstevel@tonic-gate 		return (0);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	if (arg_class &&
6997c478bd9Sstevel@tonic-gate 	    strcmp(arg_class, sep->se_class) != 0) {
7007c478bd9Sstevel@tonic-gate 		return (0);
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (arg_subclass &&
7047c478bd9Sstevel@tonic-gate 	    strcmp(arg_subclass, sep->se_subclass) != 0) {
7057c478bd9Sstevel@tonic-gate 		return (0);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	if (arg_username &&
7097c478bd9Sstevel@tonic-gate 	    strcmp(arg_username, sep->se_user) != 0) {
7107c478bd9Sstevel@tonic-gate 		return (0);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	if (arg_path &&
7147c478bd9Sstevel@tonic-gate 	    strcmp(arg_path, sep->se_path) != 0) {
7157c478bd9Sstevel@tonic-gate 		return (0);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (arg_nargs > 0) {
7197c478bd9Sstevel@tonic-gate 		line = sc_strdup(sep->se_args);
7207c478bd9Sstevel@tonic-gate 		lp = line;
7217c478bd9Sstevel@tonic-gate 		for (i = 0; i < arg_nargs; i++) {
7227c478bd9Sstevel@tonic-gate 			token = next_field(&lp);
7237c478bd9Sstevel@tonic-gate 			if (strcmp(arg_args[i], token) != 0) {
7247c478bd9Sstevel@tonic-gate 				sc_strfree(line);
7257c478bd9Sstevel@tonic-gate 				return (0);
7267c478bd9Sstevel@tonic-gate 			}
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 		sc_strfree(line);
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	return (1);
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate static void
print_serecord(FILE * fp,serecord_t * sep)7357c478bd9Sstevel@tonic-gate print_serecord(FILE *fp, serecord_t *sep)
7367c478bd9Sstevel@tonic-gate {
7377c478bd9Sstevel@tonic-gate 	str_t	*line;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	line = initstr(128);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_vendor, "-") != 0) {
7427c478bd9Sstevel@tonic-gate 		strcats(line, "vendor=");
7437c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_vendor);
7447c478bd9Sstevel@tonic-gate 		strcats(line, " ");
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_publisher, "-") != 0) {
7477c478bd9Sstevel@tonic-gate 		strcats(line, "publisher=");
7487c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_publisher);
7497c478bd9Sstevel@tonic-gate 		strcats(line, " ");
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_class, "-") != 0) {
7527c478bd9Sstevel@tonic-gate 		strcats(line, "class=");
7537c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_class);
7547c478bd9Sstevel@tonic-gate 		strcats(line, " ");
7557c478bd9Sstevel@tonic-gate 		if (strcmp(sep->se_subclass, "-") != 0) {
7567c478bd9Sstevel@tonic-gate 			strcats(line, "subclass=");
7577c478bd9Sstevel@tonic-gate 			strcats(line, sep->se_subclass);
7587c478bd9Sstevel@tonic-gate 			strcats(line, " ");
7597c478bd9Sstevel@tonic-gate 		}
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_user, "-") != 0) {
7627c478bd9Sstevel@tonic-gate 		strcats(line, "username=");
7637c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_user);
7647c478bd9Sstevel@tonic-gate 		strcats(line, " ");
7657c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 	strcats(line, sep->se_path);
7677c478bd9Sstevel@tonic-gate 	if (sep->se_args) {
7687c478bd9Sstevel@tonic-gate 		strcats(line, " ");
7697c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_args);
7707c478bd9Sstevel@tonic-gate 	}
7717c478bd9Sstevel@tonic-gate 	strcats(line, "\n");
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	(void) fputs(line->s_str, fp);
7747c478bd9Sstevel@tonic-gate 	freestr(line);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate static int
restart_cmd(void)7817c478bd9Sstevel@tonic-gate restart_cmd(void)
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate 	if (system("pkill -HUP syseventd") == -1) {
7847c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_RESTART_FAILED,
7857c478bd9Sstevel@tonic-gate 			whoami, strerror(errno));
7867c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 	return (EXIT_OK);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate static str_t *
read_next_line(FILE * fp)7937c478bd9Sstevel@tonic-gate read_next_line(FILE *fp)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	char	*lp;
7967c478bd9Sstevel@tonic-gate 	str_t	*line;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	line = initstr(128);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	lp = fstrgets(line, fp);
8017c478bd9Sstevel@tonic-gate 	if (lp == NULL) {
8027c478bd9Sstevel@tonic-gate 		freestr(line);
8037c478bd9Sstevel@tonic-gate 		return (NULL);
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	*(lp + strlen(lp)-1) = 0;
8077c478bd9Sstevel@tonic-gate 	return (line);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate static serecord_t *
parse_line(str_t * line)8127c478bd9Sstevel@tonic-gate parse_line(str_t *line)
8137c478bd9Sstevel@tonic-gate {
8147c478bd9Sstevel@tonic-gate 	char	*lp;
8157c478bd9Sstevel@tonic-gate 	char	*vendor, *publisher;
8167c478bd9Sstevel@tonic-gate 	char	*class, *subclass;
8177c478bd9Sstevel@tonic-gate 	char	*user;
8187c478bd9Sstevel@tonic-gate 	char	*reserved1, *reserved2;
8197c478bd9Sstevel@tonic-gate 	char	*path, *args;
8207c478bd9Sstevel@tonic-gate 	serecord_t *sep;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	lp = line->s_str;
8237c478bd9Sstevel@tonic-gate 	if (*lp == 0 || *lp == '#') {
8247c478bd9Sstevel@tonic-gate 		return (NULL);
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	if ((class = next_field(&lp)) != NULL) {
8287c478bd9Sstevel@tonic-gate 		subclass = next_field(&lp);
8297c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8307c478bd9Sstevel@tonic-gate 			return (NULL);
8317c478bd9Sstevel@tonic-gate 		vendor = next_field(&lp);
8327c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8337c478bd9Sstevel@tonic-gate 			return (NULL);
8347c478bd9Sstevel@tonic-gate 		publisher = next_field(&lp);
8357c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8367c478bd9Sstevel@tonic-gate 			return (NULL);
8377c478bd9Sstevel@tonic-gate 		user = next_field(&lp);
8387c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8397c478bd9Sstevel@tonic-gate 			return (NULL);
8407c478bd9Sstevel@tonic-gate 		reserved1 = next_field(&lp);
8417c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8427c478bd9Sstevel@tonic-gate 			return (NULL);
8437c478bd9Sstevel@tonic-gate 		reserved2 = next_field(&lp);
8447c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8457c478bd9Sstevel@tonic-gate 			return (NULL);
8467c478bd9Sstevel@tonic-gate 		path = next_field(&lp);
8477c478bd9Sstevel@tonic-gate 		if (lp == NULL)
8487c478bd9Sstevel@tonic-gate 			return (NULL);
8497c478bd9Sstevel@tonic-gate 		args = skip_spaces(&lp);
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	sep = sc_malloc(sizeof (serecord_t));
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	sep->se_vendor = sc_strdup(vendor);
8557c478bd9Sstevel@tonic-gate 	sep->se_publisher = sc_strdup(publisher);
8567c478bd9Sstevel@tonic-gate 	sep->se_class = sc_strdup(class);
8577c478bd9Sstevel@tonic-gate 	sep->se_subclass = sc_strdup(subclass);
8587c478bd9Sstevel@tonic-gate 	sep->se_user = sc_strdup(user);
8597c478bd9Sstevel@tonic-gate 	sep->se_reserved1 = sc_strdup(reserved1);
8607c478bd9Sstevel@tonic-gate 	sep->se_reserved2 = sc_strdup(reserved2);
8617c478bd9Sstevel@tonic-gate 	sep->se_path = sc_strdup(path);
8627c478bd9Sstevel@tonic-gate 	sep->se_args = (args == NULL) ? NULL : sc_strdup(args);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	return (sep);
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate static void
free_serecord(serecord_t * sep)8697c478bd9Sstevel@tonic-gate free_serecord(serecord_t *sep)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_vendor);
8727c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_publisher);
8737c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_class);
8747c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_subclass);
8757c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_user);
8767c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_reserved1);
8777c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_reserved2);
8787c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_path);
8797c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_args);
8807c478bd9Sstevel@tonic-gate 	sc_free(sep, sizeof (serecord_t));
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * skip_spaces() - skip to next non-space character
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate static char *
skip_spaces(char ** cpp)8887c478bd9Sstevel@tonic-gate skip_spaces(char **cpp)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	char *cp = *cpp;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
8937c478bd9Sstevel@tonic-gate 		cp++;
8947c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
8957c478bd9Sstevel@tonic-gate 		*cpp = 0;
8967c478bd9Sstevel@tonic-gate 		return (NULL);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 	return (cp);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate /*
9037c478bd9Sstevel@tonic-gate  * Get next white-space separated field.
9047c478bd9Sstevel@tonic-gate  * next_field() will not check any characters on next line.
9057c478bd9Sstevel@tonic-gate  * Each entry is composed of a single line.
9067c478bd9Sstevel@tonic-gate  */
9077c478bd9Sstevel@tonic-gate static char *
next_field(char ** cpp)9087c478bd9Sstevel@tonic-gate next_field(char **cpp)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate 	char *cp = *cpp;
9117c478bd9Sstevel@tonic-gate 	char *start;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
9147c478bd9Sstevel@tonic-gate 		cp++;
9157c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
9167c478bd9Sstevel@tonic-gate 		*cpp = 0;
9177c478bd9Sstevel@tonic-gate 		return (NULL);
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 	start = cp;
9207c478bd9Sstevel@tonic-gate 	while (*cp && *cp != ' ' && *cp != '\t')
9217c478bd9Sstevel@tonic-gate 		cp++;
9227c478bd9Sstevel@tonic-gate 	if (*cp != 0)
9237c478bd9Sstevel@tonic-gate 		*cp++ = 0;
9247c478bd9Sstevel@tonic-gate 	*cpp = cp;
9257c478bd9Sstevel@tonic-gate 	return (start);
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate  * The following functions are simple wrappers/equivalents
9327c478bd9Sstevel@tonic-gate  * for malloc, realloc, free, strdup and a special free
9337c478bd9Sstevel@tonic-gate  * for strdup.
9347c478bd9Sstevel@tonic-gate  */
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate static void *
sc_malloc(size_t n)9377c478bd9Sstevel@tonic-gate sc_malloc(size_t n)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	void *p;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	p = malloc(n);
9427c478bd9Sstevel@tonic-gate 	if (p == NULL) {
9437c478bd9Sstevel@tonic-gate 		no_mem_err();
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 	return (p);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9497c478bd9Sstevel@tonic-gate static void *
sc_realloc(void * p,size_t current,size_t n)9507c478bd9Sstevel@tonic-gate sc_realloc(void *p, size_t current, size_t n)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate 	p = realloc(p, n);
9537c478bd9Sstevel@tonic-gate 	if (p == NULL) {
9547c478bd9Sstevel@tonic-gate 		no_mem_err();
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 	return (p);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9617c478bd9Sstevel@tonic-gate static void
sc_free(void * p,size_t n)9627c478bd9Sstevel@tonic-gate sc_free(void *p, size_t n)
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	free(p);
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate static char *
sc_strdup(char * cp)9697c478bd9Sstevel@tonic-gate sc_strdup(char *cp)
9707c478bd9Sstevel@tonic-gate {
9717c478bd9Sstevel@tonic-gate 	char *new;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	new = malloc((unsigned)(strlen(cp) + 1));
9747c478bd9Sstevel@tonic-gate 	if (new == NULL) {
9757c478bd9Sstevel@tonic-gate 		no_mem_err();
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 	(void) strcpy(new, cp);
9787c478bd9Sstevel@tonic-gate 	return (new);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate static void
sc_strfree(char * s)9837c478bd9Sstevel@tonic-gate sc_strfree(char *s)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate 	if (s)
9867c478bd9Sstevel@tonic-gate 		free(s);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate  * The following functions provide some simple dynamic string
9927c478bd9Sstevel@tonic-gate  * capability.  This module has no hard-coded maximum string
9937c478bd9Sstevel@tonic-gate  * lengths and should be able to parse and generate arbitrarily
9947c478bd9Sstevel@tonic-gate  * long strings, macro expansion and command lines.
9957c478bd9Sstevel@tonic-gate  *
9967c478bd9Sstevel@tonic-gate  * Each string must be explicitly allocated and freed.
9977c478bd9Sstevel@tonic-gate  */
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate /*
10007c478bd9Sstevel@tonic-gate  * Allocate a dynamic string, with a hint to indicate how
10017c478bd9Sstevel@tonic-gate  * much memory to dynamically add to the string as it grows
10027c478bd9Sstevel@tonic-gate  * beyond its existing bounds, so as to avoid excessive
10037c478bd9Sstevel@tonic-gate  * reallocs as a string grows.
10047c478bd9Sstevel@tonic-gate  */
10057c478bd9Sstevel@tonic-gate static str_t *
initstr(int hint)10067c478bd9Sstevel@tonic-gate initstr(int hint)
10077c478bd9Sstevel@tonic-gate {
10087c478bd9Sstevel@tonic-gate 	str_t	*str;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	str = sc_malloc(sizeof (str_t));
10117c478bd9Sstevel@tonic-gate 	str->s_str = NULL;
10127c478bd9Sstevel@tonic-gate 	str->s_len = 0;
10137c478bd9Sstevel@tonic-gate 	str->s_alloc = 0;
10147c478bd9Sstevel@tonic-gate 	str->s_hint = hint;
10157c478bd9Sstevel@tonic-gate 	return (str);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate /*
10207c478bd9Sstevel@tonic-gate  * Free a dynamically-allocated string
10217c478bd9Sstevel@tonic-gate  */
10227c478bd9Sstevel@tonic-gate static void
freestr(str_t * str)10237c478bd9Sstevel@tonic-gate freestr(str_t *str)
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	if (str->s_str) {
10267c478bd9Sstevel@tonic-gate 		sc_free(str->s_str, str->s_alloc);
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 	sc_free(str, sizeof (str_t));
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate /*
10337c478bd9Sstevel@tonic-gate  * Reset a dynamically-allocated string, allows reuse
10347c478bd9Sstevel@tonic-gate  * rather than freeing the old and allocating a new one.
10357c478bd9Sstevel@tonic-gate  */
10367c478bd9Sstevel@tonic-gate static void
resetstr(str_t * str)10377c478bd9Sstevel@tonic-gate resetstr(str_t *str)
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	str->s_len = 0;
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate /*
10447c478bd9Sstevel@tonic-gate  * Concatenate a (simple) string onto a dynamically-allocated string
10457c478bd9Sstevel@tonic-gate  */
10467c478bd9Sstevel@tonic-gate static void
strcats(str_t * str,char * s)10477c478bd9Sstevel@tonic-gate strcats(str_t *str, char *s)
10487c478bd9Sstevel@tonic-gate {
10497c478bd9Sstevel@tonic-gate 	char	*new_str;
10507c478bd9Sstevel@tonic-gate 	int	len = str->s_len + strlen(s) + 1;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
10537c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
10547c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
10557c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
10567c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 	(void) strcpy(str->s_str + str->s_len, s);
10597c478bd9Sstevel@tonic-gate 	str->s_len = len - 1;
10607c478bd9Sstevel@tonic-gate }
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate /*
10647c478bd9Sstevel@tonic-gate  * Concatenate a character onto a dynamically-allocated string
10657c478bd9Sstevel@tonic-gate  */
10667c478bd9Sstevel@tonic-gate static void
strcatc(str_t * str,int c)10677c478bd9Sstevel@tonic-gate strcatc(str_t *str, int c)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate 	char	*new_str;
10707c478bd9Sstevel@tonic-gate 	int	len = str->s_len + 2;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
10737c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
10747c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
10757c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
10767c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 	*(str->s_str + str->s_len) = (char)c;
10797c478bd9Sstevel@tonic-gate 	*(str->s_str + str->s_len + 1) = 0;
10807c478bd9Sstevel@tonic-gate 	str->s_len++;
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate /*
10847c478bd9Sstevel@tonic-gate  * fgets() equivalent using a dynamically-allocated string
10857c478bd9Sstevel@tonic-gate  */
10867c478bd9Sstevel@tonic-gate static char *
fstrgets(str_t * line,FILE * fp)10877c478bd9Sstevel@tonic-gate fstrgets(str_t *line, FILE *fp)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate 	int	c;
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	resetstr(line);
10927c478bd9Sstevel@tonic-gate 	while ((c = fgetc(fp)) != EOF) {
10937c478bd9Sstevel@tonic-gate 		strcatc(line, c);
10947c478bd9Sstevel@tonic-gate 		if (c == '\n')
10957c478bd9Sstevel@tonic-gate 			break;
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 	if (line->s_len == 0)
10987c478bd9Sstevel@tonic-gate 		return (NULL);
10997c478bd9Sstevel@tonic-gate 	return (line->s_str);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate #define	INITIAL_LISTSIZE	4
11057c478bd9Sstevel@tonic-gate #define	INCR_LISTSIZE		4
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate static char **
build_strlist(char ** argvlist,int * size,int * alloc,char * str)11087c478bd9Sstevel@tonic-gate build_strlist(
11097c478bd9Sstevel@tonic-gate 	char 	**argvlist,
11107c478bd9Sstevel@tonic-gate 	int	*size,
11117c478bd9Sstevel@tonic-gate 	int	*alloc,
11127c478bd9Sstevel@tonic-gate 	char	*str)
11137c478bd9Sstevel@tonic-gate {
11147c478bd9Sstevel@tonic-gate 	int	n;
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	if (*size + 1 > *alloc) {
11177c478bd9Sstevel@tonic-gate 		if (*alloc == 0) {
11187c478bd9Sstevel@tonic-gate 			*alloc = INITIAL_LISTSIZE;
11197c478bd9Sstevel@tonic-gate 			n = sizeof (char *) * (*alloc + 1);
11207c478bd9Sstevel@tonic-gate 			argvlist = (char **)malloc(n);
11217c478bd9Sstevel@tonic-gate 			if (argvlist == NULL)
11227c478bd9Sstevel@tonic-gate 				no_mem_err();
11237c478bd9Sstevel@tonic-gate 		} else {
11247c478bd9Sstevel@tonic-gate 			*alloc += INCR_LISTSIZE;
11257c478bd9Sstevel@tonic-gate 			n = sizeof (char *) * (*alloc + 1);
11267c478bd9Sstevel@tonic-gate 			argvlist = (char **)realloc(argvlist, n);
11277c478bd9Sstevel@tonic-gate 			if (argvlist == NULL)
11287c478bd9Sstevel@tonic-gate 				no_mem_err();
11297c478bd9Sstevel@tonic-gate 		}
11307c478bd9Sstevel@tonic-gate 	}
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	argvlist[*size] = strdup(str);
11337c478bd9Sstevel@tonic-gate 	*size += 1;
11347c478bd9Sstevel@tonic-gate 	argvlist[*size] = NULL;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	return (argvlist);
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate static void
no_mem_err()11407c478bd9Sstevel@tonic-gate no_mem_err()
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_NO_MEM, whoami);
11437c478bd9Sstevel@tonic-gate 	exit_lock();
11447c478bd9Sstevel@tonic-gate 	exit(EXIT_NO_MEM);
11457c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
11467c478bd9Sstevel@tonic-gate }
1147