xref: /illumos-gate/usr/src/cmd/ctwatch/ctwatch.c (revision 7c478bd9)
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 #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <unistd.h>
36*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
37*7c478bd9Sstevel@tonic-gate #include <string.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate #include <limits.h>
40*7c478bd9Sstevel@tonic-gate #include <libcontract.h>
41*7c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
42*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
43*7c478bd9Sstevel@tonic-gate #include <poll.h>
44*7c478bd9Sstevel@tonic-gate #include <port.h>
45*7c478bd9Sstevel@tonic-gate #include <signal.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
47*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #include <locale.h>
50*7c478bd9Sstevel@tonic-gate #include <langinfo.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate struct {
53*7c478bd9Sstevel@tonic-gate 	const char *name;
54*7c478bd9Sstevel@tonic-gate 	int found;
55*7c478bd9Sstevel@tonic-gate } types[] = {
56*7c478bd9Sstevel@tonic-gate 	{ "process", 0 },
57*7c478bd9Sstevel@tonic-gate 	{ NULL }
58*7c478bd9Sstevel@tonic-gate };
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate typedef struct watched_fd {
61*7c478bd9Sstevel@tonic-gate 	int wf_fd;
62*7c478bd9Sstevel@tonic-gate 	int wf_type;
63*7c478bd9Sstevel@tonic-gate } watched_fd_t;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * usage
67*7c478bd9Sstevel@tonic-gate  *
68*7c478bd9Sstevel@tonic-gate  * Educate the user.
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate static void
71*7c478bd9Sstevel@tonic-gate usage(void)
72*7c478bd9Sstevel@tonic-gate {
73*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
74*7c478bd9Sstevel@tonic-gate 	    "Usage: %s [-f] [-r] [-v] contract-id | contract-type ...\n"),
75*7c478bd9Sstevel@tonic-gate 	    uu_getpname());
76*7c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
77*7c478bd9Sstevel@tonic-gate }
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate /*
80*7c478bd9Sstevel@tonic-gate  * sopen
81*7c478bd9Sstevel@tonic-gate  *
82*7c478bd9Sstevel@tonic-gate  * Given a format string and a variable number of arguments, create a
83*7c478bd9Sstevel@tonic-gate  * file name and open it.  Warn with 'permerror' and return -1 if
84*7c478bd9Sstevel@tonic-gate  * opening the file returned EPERM or EACCES, die with 'error' on all
85*7c478bd9Sstevel@tonic-gate  * other error conditions.
86*7c478bd9Sstevel@tonic-gate  */
87*7c478bd9Sstevel@tonic-gate static int
88*7c478bd9Sstevel@tonic-gate sopen(const char *format, const char *error, const char *permerror, ...)
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate 	char path[PATH_MAX];
91*7c478bd9Sstevel@tonic-gate 	int fd;
92*7c478bd9Sstevel@tonic-gate 	va_list varg;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	va_start(varg, permerror);
95*7c478bd9Sstevel@tonic-gate 	if (vsnprintf(path, PATH_MAX, format, varg) >= PATH_MAX) {
96*7c478bd9Sstevel@tonic-gate 		errno = ENAMETOOLONG;
97*7c478bd9Sstevel@tonic-gate 		uu_vdie(error, varg);
98*7c478bd9Sstevel@tonic-gate 	}
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	if ((fd = open64(path, O_RDONLY | O_NONBLOCK)) == -1) {
101*7c478bd9Sstevel@tonic-gate 		if (permerror && (errno == EPERM || errno == EACCES))
102*7c478bd9Sstevel@tonic-gate 			uu_vwarn(permerror, varg);
103*7c478bd9Sstevel@tonic-gate 		else
104*7c478bd9Sstevel@tonic-gate 			uu_vdie(error, varg);
105*7c478bd9Sstevel@tonic-gate 	}
106*7c478bd9Sstevel@tonic-gate 	va_end(varg);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	return (fd);
109*7c478bd9Sstevel@tonic-gate }
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * hdr_event
113*7c478bd9Sstevel@tonic-gate  *
114*7c478bd9Sstevel@tonic-gate  * Display the output header.
115*7c478bd9Sstevel@tonic-gate  */
116*7c478bd9Sstevel@tonic-gate static void
117*7c478bd9Sstevel@tonic-gate hdr_event(void)
118*7c478bd9Sstevel@tonic-gate {
119*7c478bd9Sstevel@tonic-gate 	(void) printf("%-8s%-8s%-5s%-4s%-9s%s\n",
120*7c478bd9Sstevel@tonic-gate 	    "CTID", "EVID", "CRIT", "ACK", "CTTYPE", "SUMMARY");
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate /*
124*7c478bd9Sstevel@tonic-gate  * get_event
125*7c478bd9Sstevel@tonic-gate  *
126*7c478bd9Sstevel@tonic-gate  * Read and display a contract event.
127*7c478bd9Sstevel@tonic-gate  */
128*7c478bd9Sstevel@tonic-gate static int
129*7c478bd9Sstevel@tonic-gate get_event(int fd, int type, int verbose)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	ct_evthdl_t ev;
132*7c478bd9Sstevel@tonic-gate 	uint_t flags;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	/*
135*7c478bd9Sstevel@tonic-gate 	 * Read a contract event.
136*7c478bd9Sstevel@tonic-gate 	 */
137*7c478bd9Sstevel@tonic-gate 	if (errno = ct_event_read(fd, &ev)) {
138*7c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
139*7c478bd9Sstevel@tonic-gate 			return (0);
140*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("could not receive contract event"));
141*7c478bd9Sstevel@tonic-gate 	}
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/*
144*7c478bd9Sstevel@tonic-gate 	 * Emit a one-line event summary.
145*7c478bd9Sstevel@tonic-gate 	 */
146*7c478bd9Sstevel@tonic-gate 	flags = ct_event_get_flags(ev);
147*7c478bd9Sstevel@tonic-gate 	(void) printf("%-8ld%-8lld%-5s%-4s%-9s",
148*7c478bd9Sstevel@tonic-gate 	    ct_event_get_ctid(ev),
149*7c478bd9Sstevel@tonic-gate 	    ct_event_get_evid(ev),
150*7c478bd9Sstevel@tonic-gate 	    (flags & CTE_INFO) ? "info" : (flags & CTE_NEG) ? "neg" : "crit",
151*7c478bd9Sstevel@tonic-gate 	    flags & CTE_ACK ? "yes" : "no",
152*7c478bd9Sstevel@tonic-gate 	    types[type].name);
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	/*
155*7c478bd9Sstevel@tonic-gate 	 * Display event details, if requested.
156*7c478bd9Sstevel@tonic-gate 	 * (Since this is also needed by ctrun, the common
157*7c478bd9Sstevel@tonic-gate 	 * contract_event_dump is found in libcontract.)
158*7c478bd9Sstevel@tonic-gate 	 */
159*7c478bd9Sstevel@tonic-gate 	contract_event_dump(stdout, ev, verbose);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	ct_event_free(ev);
162*7c478bd9Sstevel@tonic-gate 	return (1);
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate  * get_type
167*7c478bd9Sstevel@tonic-gate  *
168*7c478bd9Sstevel@tonic-gate  * Given a contract type name, return an index into the 'types' array.
169*7c478bd9Sstevel@tonic-gate  * Exits on failure.
170*7c478bd9Sstevel@tonic-gate  */
171*7c478bd9Sstevel@tonic-gate static int
172*7c478bd9Sstevel@tonic-gate get_type(const char *typestr)
173*7c478bd9Sstevel@tonic-gate {
174*7c478bd9Sstevel@tonic-gate 	int i;
175*7c478bd9Sstevel@tonic-gate 	for (i = 0; types[i].name; i++)
176*7c478bd9Sstevel@tonic-gate 		if (strcmp(types[i].name, typestr) == 0)
177*7c478bd9Sstevel@tonic-gate 			return (i);
178*7c478bd9Sstevel@tonic-gate 	uu_die(gettext("invalid contract type: %s\n"), typestr);
179*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * contract_type
184*7c478bd9Sstevel@tonic-gate  *
185*7c478bd9Sstevel@tonic-gate  * Given a contract id, return an index into the 'types' array.
186*7c478bd9Sstevel@tonic-gate  * Returns -1 on failure.
187*7c478bd9Sstevel@tonic-gate  */
188*7c478bd9Sstevel@tonic-gate static int
189*7c478bd9Sstevel@tonic-gate contract_type(ctid_t id)
190*7c478bd9Sstevel@tonic-gate {
191*7c478bd9Sstevel@tonic-gate 	ct_stathdl_t hdl;
192*7c478bd9Sstevel@tonic-gate 	int type, fd;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/*
195*7c478bd9Sstevel@tonic-gate 	 * This could be faster (e.g. by reading the link itself), but
196*7c478bd9Sstevel@tonic-gate 	 * this is the most straightforward implementation.
197*7c478bd9Sstevel@tonic-gate 	 */
198*7c478bd9Sstevel@tonic-gate 	if ((fd = contract_open(id, NULL, "status", O_RDONLY)) == -1)
199*7c478bd9Sstevel@tonic-gate 		return (-1);
200*7c478bd9Sstevel@tonic-gate 	if (errno = ct_status_read(fd, CTD_COMMON, &hdl)) {
201*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
202*7c478bd9Sstevel@tonic-gate 		return (-1);
203*7c478bd9Sstevel@tonic-gate 	}
204*7c478bd9Sstevel@tonic-gate 	type = get_type(ct_status_get_type(hdl));
205*7c478bd9Sstevel@tonic-gate 	ct_status_free(hdl);
206*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
207*7c478bd9Sstevel@tonic-gate 	return (type);
208*7c478bd9Sstevel@tonic-gate }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate  * ctid_compar
212*7c478bd9Sstevel@tonic-gate  *
213*7c478bd9Sstevel@tonic-gate  * A simple contract ID comparator.
214*7c478bd9Sstevel@tonic-gate  */
215*7c478bd9Sstevel@tonic-gate static int
216*7c478bd9Sstevel@tonic-gate ctid_compar(const void *a1, const void *a2)
217*7c478bd9Sstevel@tonic-gate {
218*7c478bd9Sstevel@tonic-gate 	ctid_t id1 = *(ctid_t *)a1;
219*7c478bd9Sstevel@tonic-gate 	ctid_t id2 = *(ctid_t *)a2;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	if (id1 > id2)
222*7c478bd9Sstevel@tonic-gate 		return (1);
223*7c478bd9Sstevel@tonic-gate 	if (id2 > id1)
224*7c478bd9Sstevel@tonic-gate 		return (-1);
225*7c478bd9Sstevel@tonic-gate 	return (0);
226*7c478bd9Sstevel@tonic-gate }
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate int
229*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
230*7c478bd9Sstevel@tonic-gate {
231*7c478bd9Sstevel@tonic-gate 	int	opt_reliable = 0;
232*7c478bd9Sstevel@tonic-gate 	int	opt_reset = 0;
233*7c478bd9Sstevel@tonic-gate 	int	opt_verbose = 0;
234*7c478bd9Sstevel@tonic-gate 	int	port_fd;
235*7c478bd9Sstevel@tonic-gate 	watched_fd_t *wfd;
236*7c478bd9Sstevel@tonic-gate 	int	i, nfds, nids;
237*7c478bd9Sstevel@tonic-gate 	ctid_t	*ids, last;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
240*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	while ((i = getopt(argc, argv, "rfv")) !=  EOF) {
245*7c478bd9Sstevel@tonic-gate 		switch (i) {
246*7c478bd9Sstevel@tonic-gate 		case 'r':
247*7c478bd9Sstevel@tonic-gate 			opt_reliable = 1;
248*7c478bd9Sstevel@tonic-gate 			break;
249*7c478bd9Sstevel@tonic-gate 		case 'f':
250*7c478bd9Sstevel@tonic-gate 			opt_reset = 1;
251*7c478bd9Sstevel@tonic-gate 			break;
252*7c478bd9Sstevel@tonic-gate 		case 'v':
253*7c478bd9Sstevel@tonic-gate 			opt_verbose = 1;
254*7c478bd9Sstevel@tonic-gate 			break;
255*7c478bd9Sstevel@tonic-gate 		default:
256*7c478bd9Sstevel@tonic-gate 			usage();
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	argc -= optind;
261*7c478bd9Sstevel@tonic-gate 	argv += optind;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (argc <= 0)
264*7c478bd9Sstevel@tonic-gate 		usage();
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	wfd = calloc(argc, sizeof (struct pollfd));
267*7c478bd9Sstevel@tonic-gate 	if (wfd == NULL)
268*7c478bd9Sstevel@tonic-gate 		uu_die("calloc");
269*7c478bd9Sstevel@tonic-gate 	ids = calloc(argc, sizeof (ctid_t));
270*7c478bd9Sstevel@tonic-gate 	if (ids == NULL)
271*7c478bd9Sstevel@tonic-gate 		uu_die("calloc");
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	/*
274*7c478bd9Sstevel@tonic-gate 	 * Scan our operands for contract ids and types.
275*7c478bd9Sstevel@tonic-gate 	 */
276*7c478bd9Sstevel@tonic-gate 	nfds = 0;
277*7c478bd9Sstevel@tonic-gate 	nids = 0;
278*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
279*7c478bd9Sstevel@tonic-gate 		int id;
280*7c478bd9Sstevel@tonic-gate 		if (strchr(argv[i], '/') != NULL)
281*7c478bd9Sstevel@tonic-gate 			uu_die(gettext("invalid contract type: %s\n"), argv[i]);
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 		/*
284*7c478bd9Sstevel@tonic-gate 		 * If argument isn't a number between 0 and INT_MAX,
285*7c478bd9Sstevel@tonic-gate 		 * treat it as a contract type.
286*7c478bd9Sstevel@tonic-gate 		 */
287*7c478bd9Sstevel@tonic-gate 		if (uu_strtoint(argv[i], &id, sizeof (id), 10, 1, INT_MAX)) {
288*7c478bd9Sstevel@tonic-gate 			int type;
289*7c478bd9Sstevel@tonic-gate 			wfd[nfds].wf_fd =
290*7c478bd9Sstevel@tonic-gate 			    sopen(CTFS_ROOT "/%s/bundle",
291*7c478bd9Sstevel@tonic-gate 			    gettext("invalid contract type: %s\n"), NULL,
292*7c478bd9Sstevel@tonic-gate 			    argv[i]);
293*7c478bd9Sstevel@tonic-gate 			wfd[nfds].wf_type = type = get_type(argv[i]);
294*7c478bd9Sstevel@tonic-gate 			if (types[type].found) {
295*7c478bd9Sstevel@tonic-gate 				(void) close(wfd[nfds].wf_fd);
296*7c478bd9Sstevel@tonic-gate 				continue;
297*7c478bd9Sstevel@tonic-gate 			}
298*7c478bd9Sstevel@tonic-gate 			types[type].found = 1;
299*7c478bd9Sstevel@tonic-gate 			nfds++;
300*7c478bd9Sstevel@tonic-gate 		} else {
301*7c478bd9Sstevel@tonic-gate 			ids[nids++] = id;
302*7c478bd9Sstevel@tonic-gate 		}
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	/*
306*7c478bd9Sstevel@tonic-gate 	 * Eliminate those contract ids which are represented by
307*7c478bd9Sstevel@tonic-gate 	 * contract types, so we don't get duplicate event reports from
308*7c478bd9Sstevel@tonic-gate 	 * them.
309*7c478bd9Sstevel@tonic-gate 	 *
310*7c478bd9Sstevel@tonic-gate 	 * Sorting the array first allows us to efficiently skip
311*7c478bd9Sstevel@tonic-gate 	 * duplicate ids.  We know that the array only contains
312*7c478bd9Sstevel@tonic-gate 	 * integers [0, INT_MAX].
313*7c478bd9Sstevel@tonic-gate 	 */
314*7c478bd9Sstevel@tonic-gate 	qsort(ids, nids, sizeof (ctid_t), ctid_compar);
315*7c478bd9Sstevel@tonic-gate 	last = -1;
316*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nids; i++) {
317*7c478bd9Sstevel@tonic-gate 		int type, fd;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 		if (ids[i] == last)
320*7c478bd9Sstevel@tonic-gate 			continue;
321*7c478bd9Sstevel@tonic-gate 		last = ids[i];
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 		fd = sopen(CTFS_ROOT "/all/%d/events",
324*7c478bd9Sstevel@tonic-gate 		    gettext("invalid contract id: %d\n"),
325*7c478bd9Sstevel@tonic-gate 		    gettext("could not access contract id %d\n"), ids[i]);
326*7c478bd9Sstevel@tonic-gate 		if (fd == -1)
327*7c478bd9Sstevel@tonic-gate 			continue;
328*7c478bd9Sstevel@tonic-gate 		if ((type = contract_type(ids[i])) == -1) {
329*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
330*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("could not access contract id %d\n"),
331*7c478bd9Sstevel@tonic-gate 			    ids[i]);
332*7c478bd9Sstevel@tonic-gate 			continue;
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 		if (types[type].found) {
335*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
336*7c478bd9Sstevel@tonic-gate 			continue;
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 		wfd[nfds].wf_fd = fd;
339*7c478bd9Sstevel@tonic-gate 		wfd[nfds].wf_type = type;
340*7c478bd9Sstevel@tonic-gate 		nfds++;
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 	free(ids);
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	if (nfds == 0)
345*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("no contracts to watch\n"));
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	/*
348*7c478bd9Sstevel@tonic-gate 	 * Handle options.
349*7c478bd9Sstevel@tonic-gate 	 */
350*7c478bd9Sstevel@tonic-gate 	if (opt_reliable)
351*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nfds; i++)
352*7c478bd9Sstevel@tonic-gate 			if (ioctl(wfd[i].wf_fd, CT_ERELIABLE, NULL) == -1) {
353*7c478bd9Sstevel@tonic-gate 				uu_warn("could not request reliable events");
354*7c478bd9Sstevel@tonic-gate 				break;
355*7c478bd9Sstevel@tonic-gate 			}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	if (opt_reset)
358*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nfds; i++)
359*7c478bd9Sstevel@tonic-gate 			(void) ioctl(wfd[i].wf_fd, CT_ERESET, NULL);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	/*
363*7c478bd9Sstevel@tonic-gate 	 * Allocate an event point, and associate all our endpoint file
364*7c478bd9Sstevel@tonic-gate 	 * descriptors with it.
365*7c478bd9Sstevel@tonic-gate 	 */
366*7c478bd9Sstevel@tonic-gate 	if ((port_fd = port_create()) == -1)
367*7c478bd9Sstevel@tonic-gate 		goto port_error;
368*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nfds; i++)
369*7c478bd9Sstevel@tonic-gate 		if (port_associate(port_fd, PORT_SOURCE_FD, wfd[i].wf_fd,
370*7c478bd9Sstevel@tonic-gate 		    POLLIN, &wfd[i]) == -1)
371*7c478bd9Sstevel@tonic-gate 			goto port_error;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	/*
374*7c478bd9Sstevel@tonic-gate 	 * Loop waiting for and displaying events.
375*7c478bd9Sstevel@tonic-gate 	 */
376*7c478bd9Sstevel@tonic-gate 	hdr_event();
377*7c478bd9Sstevel@tonic-gate 	for (;;) {
378*7c478bd9Sstevel@tonic-gate 		port_event_t pe;
379*7c478bd9Sstevel@tonic-gate 		watched_fd_t *w;
380*7c478bd9Sstevel@tonic-gate 		if (port_get(port_fd, &pe, NULL) == -1) {
381*7c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
382*7c478bd9Sstevel@tonic-gate 				continue;
383*7c478bd9Sstevel@tonic-gate 			goto port_error;
384*7c478bd9Sstevel@tonic-gate 		}
385*7c478bd9Sstevel@tonic-gate 		w = pe.portev_user;
386*7c478bd9Sstevel@tonic-gate 		while (get_event(pe.portev_object, w->wf_type, opt_verbose))
387*7c478bd9Sstevel@tonic-gate 			;
388*7c478bd9Sstevel@tonic-gate 		if (port_associate(port_fd, PORT_SOURCE_FD, pe.portev_object,
389*7c478bd9Sstevel@tonic-gate 		    POLLIN, pe.portev_user) == -1)
390*7c478bd9Sstevel@tonic-gate 			goto port_error;
391*7c478bd9Sstevel@tonic-gate 	}
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate port_error:
394*7c478bd9Sstevel@tonic-gate 	uu_die(gettext("error waiting for contract events"));
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	return (1);	/* placate cc */
397*7c478bd9Sstevel@tonic-gate }
398