xref: /titanic_52/usr/src/cmd/syseventadm/syseventadm.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  *	syseventadm - command to administer the sysevent.conf registry
31*7c478bd9Sstevel@tonic-gate  *		    - administers the general purpose event framework
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  *	The current implementation of the registry using files in
34*7c478bd9Sstevel@tonic-gate  *	/etc/sysevent/config, files are named as event specifications
35*7c478bd9Sstevel@tonic-gate  *	are added with the combination of the vendor, publisher, event
36*7c478bd9Sstevel@tonic-gate  *	class and subclass strings:
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  *	[<vendor>,][<publisher>,][<class>,]sysevent.conf
39*7c478bd9Sstevel@tonic-gate  *
40*7c478bd9Sstevel@tonic-gate  */
41*7c478bd9Sstevel@tonic-gate #include <stdio.h>
42*7c478bd9Sstevel@tonic-gate #include <ctype.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
44*7c478bd9Sstevel@tonic-gate #include <dirent.h>
45*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
46*7c478bd9Sstevel@tonic-gate #include <stddef.h>
47*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
48*7c478bd9Sstevel@tonic-gate #include <dlfcn.h>
49*7c478bd9Sstevel@tonic-gate #include <door.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
52*7c478bd9Sstevel@tonic-gate #include <signal.h>
53*7c478bd9Sstevel@tonic-gate #include <strings.h>
54*7c478bd9Sstevel@tonic-gate #include <unistd.h>
55*7c478bd9Sstevel@tonic-gate #include <synch.h>
56*7c478bd9Sstevel@tonic-gate #include <syslog.h>
57*7c478bd9Sstevel@tonic-gate #include <thread.h>
58*7c478bd9Sstevel@tonic-gate #include <limits.h>
59*7c478bd9Sstevel@tonic-gate #include <locale.h>
60*7c478bd9Sstevel@tonic-gate #include <assert.h>
61*7c478bd9Sstevel@tonic-gate #include <libsysevent.h>
62*7c478bd9Sstevel@tonic-gate #include <zone.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
68*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #include "syseventadm.h"
71*7c478bd9Sstevel@tonic-gate #include "syseventadm_msg.h"
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #ifndef DEBUG
74*7c478bd9Sstevel@tonic-gate #undef	assert
75*7c478bd9Sstevel@tonic-gate #define	assert(EX) ((void)0)
76*7c478bd9Sstevel@tonic-gate #endif
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate static char	*whoami		= NULL;
79*7c478bd9Sstevel@tonic-gate static char	*root_dir	= "";
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static char	*arg_vendor	= NULL;
82*7c478bd9Sstevel@tonic-gate static char	*arg_publisher	= NULL;
83*7c478bd9Sstevel@tonic-gate static char	*arg_class	= NULL;
84*7c478bd9Sstevel@tonic-gate static char	*arg_subclass	= NULL;
85*7c478bd9Sstevel@tonic-gate static char	*arg_username	= NULL;
86*7c478bd9Sstevel@tonic-gate static char	*arg_path	= NULL;
87*7c478bd9Sstevel@tonic-gate static int	arg_nargs	= 0;
88*7c478bd9Sstevel@tonic-gate static char	**arg_args	= NULL;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static	int	lock_fd;
91*7c478bd9Sstevel@tonic-gate static	char 	lock_file[PATH_MAX + 1];
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate extern char	*optarg;
94*7c478bd9Sstevel@tonic-gate extern int	optind;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate static int
97*7c478bd9Sstevel@tonic-gate usage_gen()
98*7c478bd9Sstevel@tonic-gate {
99*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_USAGE_INTRO);
100*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_USAGE_OPTIONS);
101*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n"
102*7c478bd9Sstevel@tonic-gate 	    "\tsyseventadm add ...\n"
103*7c478bd9Sstevel@tonic-gate 	    "\tsyseventadm remove ...\n"
104*7c478bd9Sstevel@tonic-gate 	    "\tsyseventadm list ...\n"
105*7c478bd9Sstevel@tonic-gate 	    "\tsyseventadm restart\n"
106*7c478bd9Sstevel@tonic-gate 	    "\tsyseventadm help\n");
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	return (EXIT_USAGE);
109*7c478bd9Sstevel@tonic-gate }
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate static int
112*7c478bd9Sstevel@tonic-gate serve_syseventdotconf(int argc, char **argv, char *cmd)
113*7c478bd9Sstevel@tonic-gate {
114*7c478bd9Sstevel@tonic-gate 	int	c;
115*7c478bd9Sstevel@tonic-gate 	int	rval;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "R:v:p:c:s:u:")) != EOF) {
118*7c478bd9Sstevel@tonic-gate 		switch (c) {
119*7c478bd9Sstevel@tonic-gate 		case 'R':
120*7c478bd9Sstevel@tonic-gate 			/*
121*7c478bd9Sstevel@tonic-gate 			 * Alternate root path for install, etc.
122*7c478bd9Sstevel@tonic-gate 			 */
123*7c478bd9Sstevel@tonic-gate 			set_root_dir(optarg);
124*7c478bd9Sstevel@tonic-gate 			break;
125*7c478bd9Sstevel@tonic-gate 		case 'v':
126*7c478bd9Sstevel@tonic-gate 			arg_vendor = optarg;
127*7c478bd9Sstevel@tonic-gate 			break;
128*7c478bd9Sstevel@tonic-gate 		case 'p':
129*7c478bd9Sstevel@tonic-gate 			arg_publisher = optarg;
130*7c478bd9Sstevel@tonic-gate 			break;
131*7c478bd9Sstevel@tonic-gate 		case 'c':
132*7c478bd9Sstevel@tonic-gate 			arg_class = optarg;
133*7c478bd9Sstevel@tonic-gate 			break;
134*7c478bd9Sstevel@tonic-gate 		case 's':
135*7c478bd9Sstevel@tonic-gate 			arg_subclass = optarg;
136*7c478bd9Sstevel@tonic-gate 			break;
137*7c478bd9Sstevel@tonic-gate 		case 'u':
138*7c478bd9Sstevel@tonic-gate 			arg_username = optarg;
139*7c478bd9Sstevel@tonic-gate 			break;
140*7c478bd9Sstevel@tonic-gate 		default:
141*7c478bd9Sstevel@tonic-gate 			return (usage());
142*7c478bd9Sstevel@tonic-gate 		}
143*7c478bd9Sstevel@tonic-gate 	}
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	if (optind < argc) {
146*7c478bd9Sstevel@tonic-gate 		arg_path = argv[optind++];
147*7c478bd9Sstevel@tonic-gate 		if (optind < argc) {
148*7c478bd9Sstevel@tonic-gate 			arg_nargs = argc - optind;
149*7c478bd9Sstevel@tonic-gate 			arg_args = argv + optind;
150*7c478bd9Sstevel@tonic-gate 		}
151*7c478bd9Sstevel@tonic-gate 	}
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	enter_lock(root_dir);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "add") == 0) {
156*7c478bd9Sstevel@tonic-gate 		rval = add_cmd();
157*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(cmd, "list") == 0) {
158*7c478bd9Sstevel@tonic-gate 		rval = list_remove_cmd(CMD_LIST);
159*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(cmd, "remove") == 0) {
160*7c478bd9Sstevel@tonic-gate 		rval = list_remove_cmd(CMD_REMOVE);
161*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(cmd, "restart") == 0) {
162*7c478bd9Sstevel@tonic-gate 		rval = restart_cmd();
163*7c478bd9Sstevel@tonic-gate 	} else {
164*7c478bd9Sstevel@tonic-gate 		rval = usage();
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	exit_lock();
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	return (rval);
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate int
174*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	char	*cmd;
177*7c478bd9Sstevel@tonic-gate 	int	rval;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
181*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	if ((whoami = strrchr(argv[0], '/')) == NULL) {
184*7c478bd9Sstevel@tonic-gate 		whoami = argv[0];
185*7c478bd9Sstevel@tonic-gate 	} else {
186*7c478bd9Sstevel@tonic-gate 		whoami++;
187*7c478bd9Sstevel@tonic-gate 	}
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if (argc == 1) {
190*7c478bd9Sstevel@tonic-gate 		return (usage_gen());
191*7c478bd9Sstevel@tonic-gate 	}
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	cmd = argv[optind++];
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/* Allow non-privileged users to get the help messages */
196*7c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "help") == 0) {
197*7c478bd9Sstevel@tonic-gate 		rval = usage_gen();
198*7c478bd9Sstevel@tonic-gate 		return (rval);
199*7c478bd9Sstevel@tonic-gate 	}
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
202*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_NOT_ROOT, whoami);
203*7c478bd9Sstevel@tonic-gate 		exit(EXIT_PERM);
204*7c478bd9Sstevel@tonic-gate 	}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "evc") != 0 && getzoneid() != GLOBAL_ZONEID) {
207*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_NOT_GLOBAL, whoami);
208*7c478bd9Sstevel@tonic-gate 		exit(EXIT_PERM);
209*7c478bd9Sstevel@tonic-gate 	}
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	if (strcmp(cmd, "add") == 0 ||
212*7c478bd9Sstevel@tonic-gate 	    strcmp(cmd, "remove") == 0 || strcmp(cmd, "list") == 0 ||
213*7c478bd9Sstevel@tonic-gate 	    strcmp(cmd, "restart") == 0) {
214*7c478bd9Sstevel@tonic-gate 		rval = serve_syseventdotconf(argc, argv, cmd);
215*7c478bd9Sstevel@tonic-gate 	} else {
216*7c478bd9Sstevel@tonic-gate 		rval = usage_gen();
217*7c478bd9Sstevel@tonic-gate 	}
218*7c478bd9Sstevel@tonic-gate 	return (rval);
219*7c478bd9Sstevel@tonic-gate }
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate static void
223*7c478bd9Sstevel@tonic-gate enter_lock(char *root_dir)
224*7c478bd9Sstevel@tonic-gate {
225*7c478bd9Sstevel@tonic-gate 	struct flock	lock;
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	if (snprintf(lock_file, sizeof (lock_file), "%s%s/%s", root_dir,
228*7c478bd9Sstevel@tonic-gate 	    SYSEVENT_CONFIG_DIR, LOCK_FILENAME) >= sizeof (lock_file)) {
229*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_PATH_ERR, whoami, lock_file);
230*7c478bd9Sstevel@tonic-gate 		exit(EXIT_CMD_FAILED);
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 	lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
233*7c478bd9Sstevel@tonic-gate 	if (lock_fd < 0) {
234*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_CREATE_ERR,
235*7c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
236*7c478bd9Sstevel@tonic-gate 		exit(EXIT_CMD_FAILED);
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
240*7c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
241*7c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
242*7c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate retry:
245*7c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
246*7c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR)
247*7c478bd9Sstevel@tonic-gate 			goto retry;
248*7c478bd9Sstevel@tonic-gate 		(void) close(lock_fd);
249*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_SET_ERR,
250*7c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
251*7c478bd9Sstevel@tonic-gate 		exit(EXIT_CMD_FAILED);
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate static void
257*7c478bd9Sstevel@tonic-gate exit_lock()
258*7c478bd9Sstevel@tonic-gate {
259*7c478bd9Sstevel@tonic-gate 	struct flock	lock;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
262*7c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
263*7c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
264*7c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLK, &lock) == -1) {
267*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_CLR_ERR,
268*7c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
269*7c478bd9Sstevel@tonic-gate 	}
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	if (close(lock_fd) == -1) {
272*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_LOCK_CLOSE_ERR,
273*7c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
274*7c478bd9Sstevel@tonic-gate 	}
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate static void
279*7c478bd9Sstevel@tonic-gate set_root_dir(char *dir)
280*7c478bd9Sstevel@tonic-gate {
281*7c478bd9Sstevel@tonic-gate 	root_dir = sc_strdup(dir);
282*7c478bd9Sstevel@tonic-gate }
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate static char *usage_msg[] = {
286*7c478bd9Sstevel@tonic-gate 	"\n"
287*7c478bd9Sstevel@tonic-gate 	"\tsyseventadm add [-R <rootdir>] [-v vendor] [-p publisher]\n"
288*7c478bd9Sstevel@tonic-gate 	"\t[-c class] [-s subclass] [-u username] path [args]\n"
289*7c478bd9Sstevel@tonic-gate 	"\n"
290*7c478bd9Sstevel@tonic-gate 	"\tsyseventadm remove [-R <rootdir>] [-v vendor] [-p publisher]\n"
291*7c478bd9Sstevel@tonic-gate 	"\t[-c class] [-s subclass] [-u username] [path [args]]\n"
292*7c478bd9Sstevel@tonic-gate 	"\n"
293*7c478bd9Sstevel@tonic-gate 	"\tsyseventadm list [-R <rootdir>] [-v vendor] [-p publisher]\n"
294*7c478bd9Sstevel@tonic-gate 	"\t[-c class] [-s subclass] [-u username] [path [args]]\n"
295*7c478bd9Sstevel@tonic-gate };
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate static int
298*7c478bd9Sstevel@tonic-gate usage()
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	char	**msgs;
301*7c478bd9Sstevel@tonic-gate 	int	i;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	msgs = usage_msg;
304*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (usage_msg)/sizeof (char *); i++) {
305*7c478bd9Sstevel@tonic-gate 		(void) fputs(*msgs++, stderr);
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	return (EXIT_USAGE);
309*7c478bd9Sstevel@tonic-gate }
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate static int
313*7c478bd9Sstevel@tonic-gate add_cmd(void)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	char	fname[MAXPATHLEN+1];
316*7c478bd9Sstevel@tonic-gate 	int	need_comma = 0;
317*7c478bd9Sstevel@tonic-gate 	int	noptions = 0;
318*7c478bd9Sstevel@tonic-gate 	struct stat st;
319*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
320*7c478bd9Sstevel@tonic-gate 	str_t	*line;
321*7c478bd9Sstevel@tonic-gate 	int	i;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	/*
324*7c478bd9Sstevel@tonic-gate 	 * At least one of vendor/publisher/class must be specified.
325*7c478bd9Sstevel@tonic-gate 	 * Subclass is only defined within the context of class.
326*7c478bd9Sstevel@tonic-gate 	 * For add, path must also be specified.
327*7c478bd9Sstevel@tonic-gate 	 */
328*7c478bd9Sstevel@tonic-gate 	if (arg_vendor)
329*7c478bd9Sstevel@tonic-gate 		noptions++;
330*7c478bd9Sstevel@tonic-gate 	if (arg_publisher)
331*7c478bd9Sstevel@tonic-gate 		noptions++;
332*7c478bd9Sstevel@tonic-gate 	if (arg_class)
333*7c478bd9Sstevel@tonic-gate 		noptions++;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	if (noptions == 0 || (arg_subclass && arg_class == NULL)) {
336*7c478bd9Sstevel@tonic-gate 		return (usage());
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if (arg_path == NULL)
340*7c478bd9Sstevel@tonic-gate 		return (usage());
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	/*
343*7c478bd9Sstevel@tonic-gate 	 * Generate the sysevent.conf file name
344*7c478bd9Sstevel@tonic-gate 	 */
345*7c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, root_dir);
346*7c478bd9Sstevel@tonic-gate 	(void) strcat(fname, SYSEVENT_CONFIG_DIR);
347*7c478bd9Sstevel@tonic-gate 	(void) strcat(fname, "/");
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	if (arg_vendor) {
350*7c478bd9Sstevel@tonic-gate 		(void) strcat(fname, arg_vendor);
351*7c478bd9Sstevel@tonic-gate 		need_comma = 1;
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 	if (arg_publisher) {
354*7c478bd9Sstevel@tonic-gate 		if (need_comma)
355*7c478bd9Sstevel@tonic-gate 			(void) strcat(fname, ",");
356*7c478bd9Sstevel@tonic-gate 		(void) strcat(fname, arg_publisher);
357*7c478bd9Sstevel@tonic-gate 		need_comma = 1;
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 	if (arg_class) {
360*7c478bd9Sstevel@tonic-gate 		if (need_comma)
361*7c478bd9Sstevel@tonic-gate 			(void) strcat(fname, ",");
362*7c478bd9Sstevel@tonic-gate 		(void) strcat(fname, arg_class);
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 	(void) strcat(fname, SYSEVENT_CONF_SUFFIX);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/*
367*7c478bd9Sstevel@tonic-gate 	 * Prepare the line to be written to the sysevent.conf file
368*7c478bd9Sstevel@tonic-gate 	 */
369*7c478bd9Sstevel@tonic-gate 	line = initstr(128);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	strcats(line, arg_class == NULL ? "-" : arg_class);
372*7c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	strcats(line, arg_subclass == NULL ? "-" : arg_subclass);
375*7c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	strcats(line, arg_vendor == NULL ? "-" : arg_vendor);
378*7c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	strcats(line, arg_publisher == NULL ? "-" : arg_publisher);
381*7c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	strcats(line, arg_username == NULL ? "-" : arg_username);
384*7c478bd9Sstevel@tonic-gate 	strcatc(line, ' ');
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	strcats(line, "- - ");
387*7c478bd9Sstevel@tonic-gate 	strcats(line, arg_path);
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	if (arg_nargs) {
390*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < arg_nargs; i++) {
391*7c478bd9Sstevel@tonic-gate 			strcatc(line, ' ');
392*7c478bd9Sstevel@tonic-gate 			strcats(line, arg_args[i]);
393*7c478bd9Sstevel@tonic-gate 		}
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if (stat(fname, &st) == -1) {
397*7c478bd9Sstevel@tonic-gate 		if (creat(fname, 0644) == -1) {
398*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_CREATE,
399*7c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
400*7c478bd9Sstevel@tonic-gate 			freestr(line);
401*7c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
402*7c478bd9Sstevel@tonic-gate 		}
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "a");
406*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
407*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
408*7c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
409*7c478bd9Sstevel@tonic-gate 		freestr(line);
410*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%s\n", line->s_str);
414*7c478bd9Sstevel@tonic-gate 	freestr(line);
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	if (fclose(fp) == -1) {
417*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CLOSE_ERROR,
418*7c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
419*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	if (chmod(fname, 0444) == -1) {
423*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CHMOD_ERROR,
424*7c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
425*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 	return (EXIT_OK);
428*7c478bd9Sstevel@tonic-gate }
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate static int
432*7c478bd9Sstevel@tonic-gate list_remove_cmd(int cmd)
433*7c478bd9Sstevel@tonic-gate {
434*7c478bd9Sstevel@tonic-gate 	struct dirent	*dp;
435*7c478bd9Sstevel@tonic-gate 	DIR		*dir;
436*7c478bd9Sstevel@tonic-gate 	char		path[MAXPATHLEN+1];
437*7c478bd9Sstevel@tonic-gate 	char		fname[MAXPATHLEN+1];
438*7c478bd9Sstevel@tonic-gate 	char		*suffix;
439*7c478bd9Sstevel@tonic-gate 	char		**dirlist = NULL;
440*7c478bd9Sstevel@tonic-gate 	int		list_size = 0;
441*7c478bd9Sstevel@tonic-gate 	int		list_alloc = 0;
442*7c478bd9Sstevel@tonic-gate 	char		**p;
443*7c478bd9Sstevel@tonic-gate 	int		rval;
444*7c478bd9Sstevel@tonic-gate 	int		result;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	/*
447*7c478bd9Sstevel@tonic-gate 	 * For the remove cmd, at least one of vendor/publisher/class/username
448*7c478bd9Sstevel@tonic-gate 	 * path must be specified.  Subclass is only defined within the
449*7c478bd9Sstevel@tonic-gate 	 * context of a class.
450*7c478bd9Sstevel@tonic-gate 	 */
451*7c478bd9Sstevel@tonic-gate 	if (cmd == CMD_REMOVE) {
452*7c478bd9Sstevel@tonic-gate 		int	noptions = 0;
453*7c478bd9Sstevel@tonic-gate 		if (arg_vendor)
454*7c478bd9Sstevel@tonic-gate 			noptions++;
455*7c478bd9Sstevel@tonic-gate 		if (arg_publisher)
456*7c478bd9Sstevel@tonic-gate 			noptions++;
457*7c478bd9Sstevel@tonic-gate 		if (arg_class)
458*7c478bd9Sstevel@tonic-gate 			noptions++;
459*7c478bd9Sstevel@tonic-gate 		if (arg_username)
460*7c478bd9Sstevel@tonic-gate 			noptions++;
461*7c478bd9Sstevel@tonic-gate 		if (arg_path)
462*7c478bd9Sstevel@tonic-gate 			noptions++;
463*7c478bd9Sstevel@tonic-gate 		if (noptions == 0 || (arg_subclass && arg_class == NULL)) {
464*7c478bd9Sstevel@tonic-gate 			return (usage());
465*7c478bd9Sstevel@tonic-gate 		}
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	(void) strcpy(path, root_dir);
469*7c478bd9Sstevel@tonic-gate 	(void) strcat(path, SYSEVENT_CONFIG_DIR);
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	if ((dir = opendir(path)) == NULL) {
472*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN_DIR,
473*7c478bd9Sstevel@tonic-gate 			whoami, path, strerror(errno));
474*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dir)) != NULL) {
478*7c478bd9Sstevel@tonic-gate 		if (dp->d_name[0] == '.')
479*7c478bd9Sstevel@tonic-gate 			continue;
480*7c478bd9Sstevel@tonic-gate 		if ((strlen(dp->d_name) == 0) ||
481*7c478bd9Sstevel@tonic-gate 		    (strcmp(dp->d_name, "lost+found") == 0))
482*7c478bd9Sstevel@tonic-gate 			continue;
483*7c478bd9Sstevel@tonic-gate 		suffix = strrchr(dp->d_name, ',');
484*7c478bd9Sstevel@tonic-gate 		if (suffix && strcmp(suffix, SYSEVENT_CONF_SUFFIX) == 0) {
485*7c478bd9Sstevel@tonic-gate 			(void) strcpy(fname, path);
486*7c478bd9Sstevel@tonic-gate 			(void) strcat(fname, "/");
487*7c478bd9Sstevel@tonic-gate 			(void) strcat(fname, dp->d_name);
488*7c478bd9Sstevel@tonic-gate 			dirlist = build_strlist(dirlist,
489*7c478bd9Sstevel@tonic-gate 				&list_size, &list_alloc, fname);
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	if (closedir(dir) == -1) {
494*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CLOSE_DIR_ERROR,
495*7c478bd9Sstevel@tonic-gate 			whoami, path, strerror(errno));
496*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	rval = EXIT_NO_MATCH;
500*7c478bd9Sstevel@tonic-gate 	if (dirlist) {
501*7c478bd9Sstevel@tonic-gate 		for (p = dirlist; *p != NULL; p++) {
502*7c478bd9Sstevel@tonic-gate 			switch (cmd) {
503*7c478bd9Sstevel@tonic-gate 			case CMD_LIST:
504*7c478bd9Sstevel@tonic-gate 				result = list_file(*p);
505*7c478bd9Sstevel@tonic-gate 				break;
506*7c478bd9Sstevel@tonic-gate 			case CMD_REMOVE:
507*7c478bd9Sstevel@tonic-gate 				result = remove_file(*p);
508*7c478bd9Sstevel@tonic-gate 				break;
509*7c478bd9Sstevel@tonic-gate 			}
510*7c478bd9Sstevel@tonic-gate 			if (rval == EXIT_NO_MATCH &&
511*7c478bd9Sstevel@tonic-gate 			    result != EXIT_NO_MATCH)
512*7c478bd9Sstevel@tonic-gate 				rval = result;
513*7c478bd9Sstevel@tonic-gate 		}
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	return (rval);
516*7c478bd9Sstevel@tonic-gate }
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate static int
520*7c478bd9Sstevel@tonic-gate list_file(char *fname)
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	FILE		*fp;
523*7c478bd9Sstevel@tonic-gate 	str_t		*line;
524*7c478bd9Sstevel@tonic-gate 	serecord_t	*sep;
525*7c478bd9Sstevel@tonic-gate 	int		rval = EXIT_NO_MATCH;
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "r");
528*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
529*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
530*7c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
531*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 	for (;;) {
534*7c478bd9Sstevel@tonic-gate 		line = read_next_line(fp);
535*7c478bd9Sstevel@tonic-gate 		if (line == NULL)
536*7c478bd9Sstevel@tonic-gate 			break;
537*7c478bd9Sstevel@tonic-gate 		sep = parse_line(line);
538*7c478bd9Sstevel@tonic-gate 		if (sep != NULL) {
539*7c478bd9Sstevel@tonic-gate 			if (matches_serecord(sep)) {
540*7c478bd9Sstevel@tonic-gate 				print_serecord(stdout, sep);
541*7c478bd9Sstevel@tonic-gate 				rval = EXIT_OK;
542*7c478bd9Sstevel@tonic-gate 			}
543*7c478bd9Sstevel@tonic-gate 			free_serecord(sep);
544*7c478bd9Sstevel@tonic-gate 		}
545*7c478bd9Sstevel@tonic-gate 		freestr(line);
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	return (rval);
550*7c478bd9Sstevel@tonic-gate }
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate static int
554*7c478bd9Sstevel@tonic-gate remove_file(char *fname)
555*7c478bd9Sstevel@tonic-gate {
556*7c478bd9Sstevel@tonic-gate 	FILE		*fp;
557*7c478bd9Sstevel@tonic-gate 	FILE		*tmp_fp;
558*7c478bd9Sstevel@tonic-gate 	str_t		*line;
559*7c478bd9Sstevel@tonic-gate 	char		*raw_line;
560*7c478bd9Sstevel@tonic-gate 	serecord_t	*sep;
561*7c478bd9Sstevel@tonic-gate 	char		tmp_name[MAXPATHLEN+1];
562*7c478bd9Sstevel@tonic-gate 	int		is_empty = 1;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "r");
565*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
566*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
567*7c478bd9Sstevel@tonic-gate 			whoami, fname, strerror(errno));
568*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
569*7c478bd9Sstevel@tonic-gate 	}
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	if (check_for_removes(fp) == 0) {
572*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
573*7c478bd9Sstevel@tonic-gate 		return (EXIT_NO_MATCH);
574*7c478bd9Sstevel@tonic-gate 	}
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	rewind(fp);
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	(void) strcpy(tmp_name, root_dir);
579*7c478bd9Sstevel@tonic-gate 	(void) strcat(tmp_name, SYSEVENT_CONFIG_DIR);
580*7c478bd9Sstevel@tonic-gate 	(void) strcat(tmp_name, "/tmp.XXXXXX");
581*7c478bd9Sstevel@tonic-gate 	if (mktemp(tmp_name) == NULL) {
582*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "unable to make tmp file name\n");
583*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	if (creat(tmp_name, 0644) == -1) {
587*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_CREATE,
588*7c478bd9Sstevel@tonic-gate 			whoami, tmp_name, strerror(errno));
589*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	tmp_fp = fopen(tmp_name, "a");
593*7c478bd9Sstevel@tonic-gate 	if (tmp_fp == NULL) {
594*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CANNOT_OPEN,
595*7c478bd9Sstevel@tonic-gate 			whoami, tmp_name, strerror(errno));
596*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_name);
597*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
598*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	for (;;) {
602*7c478bd9Sstevel@tonic-gate 		line = read_next_line(fp);
603*7c478bd9Sstevel@tonic-gate 		if (line == NULL)
604*7c478bd9Sstevel@tonic-gate 			break;
605*7c478bd9Sstevel@tonic-gate 		raw_line = sc_strdup(line->s_str);
606*7c478bd9Sstevel@tonic-gate 		sep = parse_line(line);
607*7c478bd9Sstevel@tonic-gate 		if (sep == NULL) {
608*7c478bd9Sstevel@tonic-gate 			(void) fputs(line->s_str, tmp_fp);
609*7c478bd9Sstevel@tonic-gate 		} else {
610*7c478bd9Sstevel@tonic-gate 			if (!matches_serecord(sep)) {
611*7c478bd9Sstevel@tonic-gate 				is_empty = 0;
612*7c478bd9Sstevel@tonic-gate 				(void) fprintf(tmp_fp, "%s\n", raw_line);
613*7c478bd9Sstevel@tonic-gate 			}
614*7c478bd9Sstevel@tonic-gate 			free_serecord(sep);
615*7c478bd9Sstevel@tonic-gate 		}
616*7c478bd9Sstevel@tonic-gate 		freestr(line);
617*7c478bd9Sstevel@tonic-gate 		sc_strfree(raw_line);
618*7c478bd9Sstevel@tonic-gate 	}
619*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
620*7c478bd9Sstevel@tonic-gate 	if (fclose(tmp_fp) == -1) {
621*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_CLOSE_ERROR,
622*7c478bd9Sstevel@tonic-gate 			whoami, tmp_name, strerror(errno));
623*7c478bd9Sstevel@tonic-gate 	}
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	if (is_empty) {
626*7c478bd9Sstevel@tonic-gate 		if (unlink(tmp_name) == -1) {
627*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_UNLINK,
628*7c478bd9Sstevel@tonic-gate 				whoami, tmp_name, strerror(errno));
629*7c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
630*7c478bd9Sstevel@tonic-gate 		}
631*7c478bd9Sstevel@tonic-gate 		if (unlink(fname) == -1) {
632*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_UNLINK,
633*7c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
634*7c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
635*7c478bd9Sstevel@tonic-gate 		}
636*7c478bd9Sstevel@tonic-gate 	} else {
637*7c478bd9Sstevel@tonic-gate 		if (unlink(fname) == -1) {
638*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_UNLINK,
639*7c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
640*7c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
641*7c478bd9Sstevel@tonic-gate 		}
642*7c478bd9Sstevel@tonic-gate 		if (rename(tmp_name, fname) == -1) {
643*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CANNOT_RENAME,
644*7c478bd9Sstevel@tonic-gate 				whoami, tmp_name, fname, strerror(errno));
645*7c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
646*7c478bd9Sstevel@tonic-gate 		}
647*7c478bd9Sstevel@tonic-gate 		if (chmod(fname, 0444) == -1) {
648*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_CHMOD_ERROR,
649*7c478bd9Sstevel@tonic-gate 				whoami, fname, strerror(errno));
650*7c478bd9Sstevel@tonic-gate 			return (EXIT_CMD_FAILED);
651*7c478bd9Sstevel@tonic-gate 		}
652*7c478bd9Sstevel@tonic-gate 	}
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	return (EXIT_OK);
655*7c478bd9Sstevel@tonic-gate }
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate static int
658*7c478bd9Sstevel@tonic-gate check_for_removes(FILE *fp)
659*7c478bd9Sstevel@tonic-gate {
660*7c478bd9Sstevel@tonic-gate 	str_t		*line;
661*7c478bd9Sstevel@tonic-gate 	serecord_t	*sep;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	for (;;) {
664*7c478bd9Sstevel@tonic-gate 		line = read_next_line(fp);
665*7c478bd9Sstevel@tonic-gate 		if (line == NULL)
666*7c478bd9Sstevel@tonic-gate 			break;
667*7c478bd9Sstevel@tonic-gate 		sep = parse_line(line);
668*7c478bd9Sstevel@tonic-gate 		if (sep != NULL) {
669*7c478bd9Sstevel@tonic-gate 			if (matches_serecord(sep)) {
670*7c478bd9Sstevel@tonic-gate 				free_serecord(sep);
671*7c478bd9Sstevel@tonic-gate 				freestr(line);
672*7c478bd9Sstevel@tonic-gate 				return (1);
673*7c478bd9Sstevel@tonic-gate 			}
674*7c478bd9Sstevel@tonic-gate 			free_serecord(sep);
675*7c478bd9Sstevel@tonic-gate 		}
676*7c478bd9Sstevel@tonic-gate 		freestr(line);
677*7c478bd9Sstevel@tonic-gate 	}
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	return (0);
680*7c478bd9Sstevel@tonic-gate }
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate static int
684*7c478bd9Sstevel@tonic-gate matches_serecord(serecord_t *sep)
685*7c478bd9Sstevel@tonic-gate {
686*7c478bd9Sstevel@tonic-gate 	char	*line;
687*7c478bd9Sstevel@tonic-gate 	char	*lp;
688*7c478bd9Sstevel@tonic-gate 	char	*token;
689*7c478bd9Sstevel@tonic-gate 	int	i;
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	if (arg_vendor &&
692*7c478bd9Sstevel@tonic-gate 	    strcmp(arg_vendor, sep->se_vendor) != 0) {
693*7c478bd9Sstevel@tonic-gate 		return (0);
694*7c478bd9Sstevel@tonic-gate 	}
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	if (arg_publisher &&
697*7c478bd9Sstevel@tonic-gate 	    strcmp(arg_publisher, sep->se_publisher) != 0) {
698*7c478bd9Sstevel@tonic-gate 		return (0);
699*7c478bd9Sstevel@tonic-gate 	}
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	if (arg_class &&
702*7c478bd9Sstevel@tonic-gate 	    strcmp(arg_class, sep->se_class) != 0) {
703*7c478bd9Sstevel@tonic-gate 		return (0);
704*7c478bd9Sstevel@tonic-gate 	}
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	if (arg_subclass &&
707*7c478bd9Sstevel@tonic-gate 	    strcmp(arg_subclass, sep->se_subclass) != 0) {
708*7c478bd9Sstevel@tonic-gate 		return (0);
709*7c478bd9Sstevel@tonic-gate 	}
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	if (arg_username &&
712*7c478bd9Sstevel@tonic-gate 	    strcmp(arg_username, sep->se_user) != 0) {
713*7c478bd9Sstevel@tonic-gate 		return (0);
714*7c478bd9Sstevel@tonic-gate 	}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	if (arg_path &&
717*7c478bd9Sstevel@tonic-gate 	    strcmp(arg_path, sep->se_path) != 0) {
718*7c478bd9Sstevel@tonic-gate 		return (0);
719*7c478bd9Sstevel@tonic-gate 	}
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	if (arg_nargs > 0) {
722*7c478bd9Sstevel@tonic-gate 		line = sc_strdup(sep->se_args);
723*7c478bd9Sstevel@tonic-gate 		lp = line;
724*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < arg_nargs; i++) {
725*7c478bd9Sstevel@tonic-gate 			token = next_field(&lp);
726*7c478bd9Sstevel@tonic-gate 			if (strcmp(arg_args[i], token) != 0) {
727*7c478bd9Sstevel@tonic-gate 				sc_strfree(line);
728*7c478bd9Sstevel@tonic-gate 				return (0);
729*7c478bd9Sstevel@tonic-gate 			}
730*7c478bd9Sstevel@tonic-gate 		}
731*7c478bd9Sstevel@tonic-gate 		sc_strfree(line);
732*7c478bd9Sstevel@tonic-gate 	}
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	return (1);
735*7c478bd9Sstevel@tonic-gate }
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate static void
738*7c478bd9Sstevel@tonic-gate print_serecord(FILE *fp, serecord_t *sep)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	str_t	*line;
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	line = initstr(128);
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_vendor, "-") != 0) {
745*7c478bd9Sstevel@tonic-gate 		strcats(line, "vendor=");
746*7c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_vendor);
747*7c478bd9Sstevel@tonic-gate 		strcats(line, " ");
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_publisher, "-") != 0) {
750*7c478bd9Sstevel@tonic-gate 		strcats(line, "publisher=");
751*7c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_publisher);
752*7c478bd9Sstevel@tonic-gate 		strcats(line, " ");
753*7c478bd9Sstevel@tonic-gate 	}
754*7c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_class, "-") != 0) {
755*7c478bd9Sstevel@tonic-gate 		strcats(line, "class=");
756*7c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_class);
757*7c478bd9Sstevel@tonic-gate 		strcats(line, " ");
758*7c478bd9Sstevel@tonic-gate 		if (strcmp(sep->se_subclass, "-") != 0) {
759*7c478bd9Sstevel@tonic-gate 			strcats(line, "subclass=");
760*7c478bd9Sstevel@tonic-gate 			strcats(line, sep->se_subclass);
761*7c478bd9Sstevel@tonic-gate 			strcats(line, " ");
762*7c478bd9Sstevel@tonic-gate 		}
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 	if (strcmp(sep->se_user, "-") != 0) {
765*7c478bd9Sstevel@tonic-gate 		strcats(line, "username=");
766*7c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_user);
767*7c478bd9Sstevel@tonic-gate 		strcats(line, " ");
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 	strcats(line, sep->se_path);
770*7c478bd9Sstevel@tonic-gate 	if (sep->se_args) {
771*7c478bd9Sstevel@tonic-gate 		strcats(line, " ");
772*7c478bd9Sstevel@tonic-gate 		strcats(line, sep->se_args);
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 	strcats(line, "\n");
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	(void) fputs(line->s_str, fp);
777*7c478bd9Sstevel@tonic-gate 	freestr(line);
778*7c478bd9Sstevel@tonic-gate }
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate static int
784*7c478bd9Sstevel@tonic-gate restart_cmd(void)
785*7c478bd9Sstevel@tonic-gate {
786*7c478bd9Sstevel@tonic-gate 	if (system("pkill -HUP syseventd") == -1) {
787*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_RESTART_FAILED,
788*7c478bd9Sstevel@tonic-gate 			whoami, strerror(errno));
789*7c478bd9Sstevel@tonic-gate 		return (EXIT_CMD_FAILED);
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate 	return (EXIT_OK);
792*7c478bd9Sstevel@tonic-gate }
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate static str_t *
796*7c478bd9Sstevel@tonic-gate read_next_line(FILE *fp)
797*7c478bd9Sstevel@tonic-gate {
798*7c478bd9Sstevel@tonic-gate 	char	*lp;
799*7c478bd9Sstevel@tonic-gate 	str_t	*line;
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	line = initstr(128);
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	lp = fstrgets(line, fp);
804*7c478bd9Sstevel@tonic-gate 	if (lp == NULL) {
805*7c478bd9Sstevel@tonic-gate 		freestr(line);
806*7c478bd9Sstevel@tonic-gate 		return (NULL);
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	*(lp + strlen(lp)-1) = 0;
810*7c478bd9Sstevel@tonic-gate 	return (line);
811*7c478bd9Sstevel@tonic-gate }
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate static serecord_t *
815*7c478bd9Sstevel@tonic-gate parse_line(str_t *line)
816*7c478bd9Sstevel@tonic-gate {
817*7c478bd9Sstevel@tonic-gate 	char	*lp;
818*7c478bd9Sstevel@tonic-gate 	char	*vendor, *publisher;
819*7c478bd9Sstevel@tonic-gate 	char	*class, *subclass;
820*7c478bd9Sstevel@tonic-gate 	char	*user;
821*7c478bd9Sstevel@tonic-gate 	char	*reserved1, *reserved2;
822*7c478bd9Sstevel@tonic-gate 	char	*path, *args;
823*7c478bd9Sstevel@tonic-gate 	serecord_t *sep;
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	lp = line->s_str;
826*7c478bd9Sstevel@tonic-gate 	if (*lp == 0 || *lp == '#') {
827*7c478bd9Sstevel@tonic-gate 		return (NULL);
828*7c478bd9Sstevel@tonic-gate 	}
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	if ((class = next_field(&lp)) != NULL) {
831*7c478bd9Sstevel@tonic-gate 		subclass = next_field(&lp);
832*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
833*7c478bd9Sstevel@tonic-gate 			return (NULL);
834*7c478bd9Sstevel@tonic-gate 		vendor = next_field(&lp);
835*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
836*7c478bd9Sstevel@tonic-gate 			return (NULL);
837*7c478bd9Sstevel@tonic-gate 		publisher = next_field(&lp);
838*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
839*7c478bd9Sstevel@tonic-gate 			return (NULL);
840*7c478bd9Sstevel@tonic-gate 		user = next_field(&lp);
841*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
842*7c478bd9Sstevel@tonic-gate 			return (NULL);
843*7c478bd9Sstevel@tonic-gate 		reserved1 = next_field(&lp);
844*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
845*7c478bd9Sstevel@tonic-gate 			return (NULL);
846*7c478bd9Sstevel@tonic-gate 		reserved2 = next_field(&lp);
847*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
848*7c478bd9Sstevel@tonic-gate 			return (NULL);
849*7c478bd9Sstevel@tonic-gate 		path = next_field(&lp);
850*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
851*7c478bd9Sstevel@tonic-gate 			return (NULL);
852*7c478bd9Sstevel@tonic-gate 		args = skip_spaces(&lp);
853*7c478bd9Sstevel@tonic-gate 	}
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	sep = sc_malloc(sizeof (serecord_t));
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	sep->se_vendor = sc_strdup(vendor);
858*7c478bd9Sstevel@tonic-gate 	sep->se_publisher = sc_strdup(publisher);
859*7c478bd9Sstevel@tonic-gate 	sep->se_class = sc_strdup(class);
860*7c478bd9Sstevel@tonic-gate 	sep->se_subclass = sc_strdup(subclass);
861*7c478bd9Sstevel@tonic-gate 	sep->se_user = sc_strdup(user);
862*7c478bd9Sstevel@tonic-gate 	sep->se_reserved1 = sc_strdup(reserved1);
863*7c478bd9Sstevel@tonic-gate 	sep->se_reserved2 = sc_strdup(reserved2);
864*7c478bd9Sstevel@tonic-gate 	sep->se_path = sc_strdup(path);
865*7c478bd9Sstevel@tonic-gate 	sep->se_args = (args == NULL) ? NULL : sc_strdup(args);
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 	return (sep);
868*7c478bd9Sstevel@tonic-gate }
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate static void
872*7c478bd9Sstevel@tonic-gate free_serecord(serecord_t *sep)
873*7c478bd9Sstevel@tonic-gate {
874*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_vendor);
875*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_publisher);
876*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_class);
877*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_subclass);
878*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_user);
879*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_reserved1);
880*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_reserved2);
881*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_path);
882*7c478bd9Sstevel@tonic-gate 	sc_strfree(sep->se_args);
883*7c478bd9Sstevel@tonic-gate 	sc_free(sep, sizeof (serecord_t));
884*7c478bd9Sstevel@tonic-gate }
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate /*
888*7c478bd9Sstevel@tonic-gate  * skip_spaces() - skip to next non-space character
889*7c478bd9Sstevel@tonic-gate  */
890*7c478bd9Sstevel@tonic-gate static char *
891*7c478bd9Sstevel@tonic-gate skip_spaces(char **cpp)
892*7c478bd9Sstevel@tonic-gate {
893*7c478bd9Sstevel@tonic-gate 	char *cp = *cpp;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
896*7c478bd9Sstevel@tonic-gate 		cp++;
897*7c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
898*7c478bd9Sstevel@tonic-gate 		*cpp = 0;
899*7c478bd9Sstevel@tonic-gate 		return (NULL);
900*7c478bd9Sstevel@tonic-gate 	}
901*7c478bd9Sstevel@tonic-gate 	return (cp);
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate /*
906*7c478bd9Sstevel@tonic-gate  * Get next white-space separated field.
907*7c478bd9Sstevel@tonic-gate  * next_field() will not check any characters on next line.
908*7c478bd9Sstevel@tonic-gate  * Each entry is composed of a single line.
909*7c478bd9Sstevel@tonic-gate  */
910*7c478bd9Sstevel@tonic-gate static char *
911*7c478bd9Sstevel@tonic-gate next_field(char **cpp)
912*7c478bd9Sstevel@tonic-gate {
913*7c478bd9Sstevel@tonic-gate 	char *cp = *cpp;
914*7c478bd9Sstevel@tonic-gate 	char *start;
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
917*7c478bd9Sstevel@tonic-gate 		cp++;
918*7c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
919*7c478bd9Sstevel@tonic-gate 		*cpp = 0;
920*7c478bd9Sstevel@tonic-gate 		return (NULL);
921*7c478bd9Sstevel@tonic-gate 	}
922*7c478bd9Sstevel@tonic-gate 	start = cp;
923*7c478bd9Sstevel@tonic-gate 	while (*cp && *cp != ' ' && *cp != '\t')
924*7c478bd9Sstevel@tonic-gate 		cp++;
925*7c478bd9Sstevel@tonic-gate 	if (*cp != 0)
926*7c478bd9Sstevel@tonic-gate 		*cp++ = 0;
927*7c478bd9Sstevel@tonic-gate 	*cpp = cp;
928*7c478bd9Sstevel@tonic-gate 	return (start);
929*7c478bd9Sstevel@tonic-gate }
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate /*
934*7c478bd9Sstevel@tonic-gate  * The following functions are simple wrappers/equivalents
935*7c478bd9Sstevel@tonic-gate  * for malloc, realloc, free, strdup and a special free
936*7c478bd9Sstevel@tonic-gate  * for strdup.
937*7c478bd9Sstevel@tonic-gate  */
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate static void *
940*7c478bd9Sstevel@tonic-gate sc_malloc(size_t n)
941*7c478bd9Sstevel@tonic-gate {
942*7c478bd9Sstevel@tonic-gate 	void *p;
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	p = malloc(n);
945*7c478bd9Sstevel@tonic-gate 	if (p == NULL) {
946*7c478bd9Sstevel@tonic-gate 		no_mem_err();
947*7c478bd9Sstevel@tonic-gate 	}
948*7c478bd9Sstevel@tonic-gate 	return (p);
949*7c478bd9Sstevel@tonic-gate }
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
952*7c478bd9Sstevel@tonic-gate static void *
953*7c478bd9Sstevel@tonic-gate sc_realloc(void *p, size_t current, size_t n)
954*7c478bd9Sstevel@tonic-gate {
955*7c478bd9Sstevel@tonic-gate 	p = realloc(p, n);
956*7c478bd9Sstevel@tonic-gate 	if (p == NULL) {
957*7c478bd9Sstevel@tonic-gate 		no_mem_err();
958*7c478bd9Sstevel@tonic-gate 	}
959*7c478bd9Sstevel@tonic-gate 	return (p);
960*7c478bd9Sstevel@tonic-gate }
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
964*7c478bd9Sstevel@tonic-gate static void
965*7c478bd9Sstevel@tonic-gate sc_free(void *p, size_t n)
966*7c478bd9Sstevel@tonic-gate {
967*7c478bd9Sstevel@tonic-gate 	free(p);
968*7c478bd9Sstevel@tonic-gate }
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate static char *
972*7c478bd9Sstevel@tonic-gate sc_strdup(char *cp)
973*7c478bd9Sstevel@tonic-gate {
974*7c478bd9Sstevel@tonic-gate 	char *new;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	new = malloc((unsigned)(strlen(cp) + 1));
977*7c478bd9Sstevel@tonic-gate 	if (new == NULL) {
978*7c478bd9Sstevel@tonic-gate 		no_mem_err();
979*7c478bd9Sstevel@tonic-gate 	}
980*7c478bd9Sstevel@tonic-gate 	(void) strcpy(new, cp);
981*7c478bd9Sstevel@tonic-gate 	return (new);
982*7c478bd9Sstevel@tonic-gate }
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate static void
986*7c478bd9Sstevel@tonic-gate sc_strfree(char *s)
987*7c478bd9Sstevel@tonic-gate {
988*7c478bd9Sstevel@tonic-gate 	if (s)
989*7c478bd9Sstevel@tonic-gate 		free(s);
990*7c478bd9Sstevel@tonic-gate }
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate /*
994*7c478bd9Sstevel@tonic-gate  * The following functions provide some simple dynamic string
995*7c478bd9Sstevel@tonic-gate  * capability.  This module has no hard-coded maximum string
996*7c478bd9Sstevel@tonic-gate  * lengths and should be able to parse and generate arbitrarily
997*7c478bd9Sstevel@tonic-gate  * long strings, macro expansion and command lines.
998*7c478bd9Sstevel@tonic-gate  *
999*7c478bd9Sstevel@tonic-gate  * Each string must be explicitly allocated and freed.
1000*7c478bd9Sstevel@tonic-gate  */
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate /*
1003*7c478bd9Sstevel@tonic-gate  * Allocate a dynamic string, with a hint to indicate how
1004*7c478bd9Sstevel@tonic-gate  * much memory to dynamically add to the string as it grows
1005*7c478bd9Sstevel@tonic-gate  * beyond its existing bounds, so as to avoid excessive
1006*7c478bd9Sstevel@tonic-gate  * reallocs as a string grows.
1007*7c478bd9Sstevel@tonic-gate  */
1008*7c478bd9Sstevel@tonic-gate static str_t *
1009*7c478bd9Sstevel@tonic-gate initstr(int hint)
1010*7c478bd9Sstevel@tonic-gate {
1011*7c478bd9Sstevel@tonic-gate 	str_t	*str;
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	str = sc_malloc(sizeof (str_t));
1014*7c478bd9Sstevel@tonic-gate 	str->s_str = NULL;
1015*7c478bd9Sstevel@tonic-gate 	str->s_len = 0;
1016*7c478bd9Sstevel@tonic-gate 	str->s_alloc = 0;
1017*7c478bd9Sstevel@tonic-gate 	str->s_hint = hint;
1018*7c478bd9Sstevel@tonic-gate 	return (str);
1019*7c478bd9Sstevel@tonic-gate }
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate /*
1023*7c478bd9Sstevel@tonic-gate  * Free a dynamically-allocated string
1024*7c478bd9Sstevel@tonic-gate  */
1025*7c478bd9Sstevel@tonic-gate static void
1026*7c478bd9Sstevel@tonic-gate freestr(str_t *str)
1027*7c478bd9Sstevel@tonic-gate {
1028*7c478bd9Sstevel@tonic-gate 	if (str->s_str) {
1029*7c478bd9Sstevel@tonic-gate 		sc_free(str->s_str, str->s_alloc);
1030*7c478bd9Sstevel@tonic-gate 	}
1031*7c478bd9Sstevel@tonic-gate 	sc_free(str, sizeof (str_t));
1032*7c478bd9Sstevel@tonic-gate }
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate /*
1036*7c478bd9Sstevel@tonic-gate  * Reset a dynamically-allocated string, allows reuse
1037*7c478bd9Sstevel@tonic-gate  * rather than freeing the old and allocating a new one.
1038*7c478bd9Sstevel@tonic-gate  */
1039*7c478bd9Sstevel@tonic-gate static void
1040*7c478bd9Sstevel@tonic-gate resetstr(str_t *str)
1041*7c478bd9Sstevel@tonic-gate {
1042*7c478bd9Sstevel@tonic-gate 	str->s_len = 0;
1043*7c478bd9Sstevel@tonic-gate }
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate /*
1047*7c478bd9Sstevel@tonic-gate  * Concatenate a (simple) string onto a dynamically-allocated string
1048*7c478bd9Sstevel@tonic-gate  */
1049*7c478bd9Sstevel@tonic-gate static void
1050*7c478bd9Sstevel@tonic-gate strcats(str_t *str, char *s)
1051*7c478bd9Sstevel@tonic-gate {
1052*7c478bd9Sstevel@tonic-gate 	char	*new_str;
1053*7c478bd9Sstevel@tonic-gate 	int	len = str->s_len + strlen(s) + 1;
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
1056*7c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
1057*7c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
1058*7c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
1059*7c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
1060*7c478bd9Sstevel@tonic-gate 	}
1061*7c478bd9Sstevel@tonic-gate 	(void) strcpy(str->s_str + str->s_len, s);
1062*7c478bd9Sstevel@tonic-gate 	str->s_len = len - 1;
1063*7c478bd9Sstevel@tonic-gate }
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate /*
1067*7c478bd9Sstevel@tonic-gate  * Concatenate a character onto a dynamically-allocated string
1068*7c478bd9Sstevel@tonic-gate  */
1069*7c478bd9Sstevel@tonic-gate static void
1070*7c478bd9Sstevel@tonic-gate strcatc(str_t *str, int c)
1071*7c478bd9Sstevel@tonic-gate {
1072*7c478bd9Sstevel@tonic-gate 	char	*new_str;
1073*7c478bd9Sstevel@tonic-gate 	int	len = str->s_len + 2;
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
1076*7c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
1077*7c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
1078*7c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
1079*7c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
1080*7c478bd9Sstevel@tonic-gate 	}
1081*7c478bd9Sstevel@tonic-gate 	*(str->s_str + str->s_len) = (char)c;
1082*7c478bd9Sstevel@tonic-gate 	*(str->s_str + str->s_len + 1) = 0;
1083*7c478bd9Sstevel@tonic-gate 	str->s_len++;
1084*7c478bd9Sstevel@tonic-gate }
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate /*
1087*7c478bd9Sstevel@tonic-gate  * fgets() equivalent using a dynamically-allocated string
1088*7c478bd9Sstevel@tonic-gate  */
1089*7c478bd9Sstevel@tonic-gate static char *
1090*7c478bd9Sstevel@tonic-gate fstrgets(str_t *line, FILE *fp)
1091*7c478bd9Sstevel@tonic-gate {
1092*7c478bd9Sstevel@tonic-gate 	int	c;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	resetstr(line);
1095*7c478bd9Sstevel@tonic-gate 	while ((c = fgetc(fp)) != EOF) {
1096*7c478bd9Sstevel@tonic-gate 		strcatc(line, c);
1097*7c478bd9Sstevel@tonic-gate 		if (c == '\n')
1098*7c478bd9Sstevel@tonic-gate 			break;
1099*7c478bd9Sstevel@tonic-gate 	}
1100*7c478bd9Sstevel@tonic-gate 	if (line->s_len == 0)
1101*7c478bd9Sstevel@tonic-gate 		return (NULL);
1102*7c478bd9Sstevel@tonic-gate 	return (line->s_str);
1103*7c478bd9Sstevel@tonic-gate }
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate #define	INITIAL_LISTSIZE	4
1108*7c478bd9Sstevel@tonic-gate #define	INCR_LISTSIZE		4
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate static char **
1111*7c478bd9Sstevel@tonic-gate build_strlist(
1112*7c478bd9Sstevel@tonic-gate 	char 	**argvlist,
1113*7c478bd9Sstevel@tonic-gate 	int	*size,
1114*7c478bd9Sstevel@tonic-gate 	int	*alloc,
1115*7c478bd9Sstevel@tonic-gate 	char	*str)
1116*7c478bd9Sstevel@tonic-gate {
1117*7c478bd9Sstevel@tonic-gate 	int	n;
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	if (*size + 1 > *alloc) {
1120*7c478bd9Sstevel@tonic-gate 		if (*alloc == 0) {
1121*7c478bd9Sstevel@tonic-gate 			*alloc = INITIAL_LISTSIZE;
1122*7c478bd9Sstevel@tonic-gate 			n = sizeof (char *) * (*alloc + 1);
1123*7c478bd9Sstevel@tonic-gate 			argvlist = (char **)malloc(n);
1124*7c478bd9Sstevel@tonic-gate 			if (argvlist == NULL)
1125*7c478bd9Sstevel@tonic-gate 				no_mem_err();
1126*7c478bd9Sstevel@tonic-gate 		} else {
1127*7c478bd9Sstevel@tonic-gate 			*alloc += INCR_LISTSIZE;
1128*7c478bd9Sstevel@tonic-gate 			n = sizeof (char *) * (*alloc + 1);
1129*7c478bd9Sstevel@tonic-gate 			argvlist = (char **)realloc(argvlist, n);
1130*7c478bd9Sstevel@tonic-gate 			if (argvlist == NULL)
1131*7c478bd9Sstevel@tonic-gate 				no_mem_err();
1132*7c478bd9Sstevel@tonic-gate 		}
1133*7c478bd9Sstevel@tonic-gate 	}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	argvlist[*size] = strdup(str);
1136*7c478bd9Sstevel@tonic-gate 	*size += 1;
1137*7c478bd9Sstevel@tonic-gate 	argvlist[*size] = NULL;
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 	return (argvlist);
1140*7c478bd9Sstevel@tonic-gate }
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate static void
1143*7c478bd9Sstevel@tonic-gate no_mem_err()
1144*7c478bd9Sstevel@tonic-gate {
1145*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_NO_MEM, whoami);
1146*7c478bd9Sstevel@tonic-gate 	exit_lock();
1147*7c478bd9Sstevel@tonic-gate 	exit(EXIT_NO_MEM);
1148*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1149*7c478bd9Sstevel@tonic-gate }
1150