4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/types.h>
31 #include <sys/contract/process.h>
39 #include <libcontract.h>
40 #include <libcontract_priv.h>
60 typedef struct watched_fd
{
73 (void) fprintf(stderr
, gettext(
74 "Usage: %s [-f] [-r] [-v] contract-id | contract-type ...\n"),
82 * Given a format string and a variable number of arguments, create a
83 * file name and open it. Warn with 'permerror' and return -1 if
84 * opening the file returned EPERM or EACCES, die with 'error' on all
85 * other error conditions.
88 sopen(const char *format
, const char *error
, const char *permerror
, ...)
94 va_start(varg
, permerror
);
95 if (vsnprintf(path
, PATH_MAX
, format
, varg
) >= PATH_MAX
) {
100 if ((fd
= open64(path
, O_RDONLY
| O_NONBLOCK
)) == -1) {
101 if (permerror
&& (errno
== EPERM
|| errno
== EACCES
))
102 uu_vwarn(permerror
, varg
);
104 uu_vdie(error
, varg
);
114 * Display the output header.
119 (void) printf("%-8s%-8s%-5s%-4s%-9s%s\n",
120 "CTID", "EVID", "CRIT", "ACK", "CTTYPE", "SUMMARY");
126 * Read and display a contract event.
129 get_event(int fd
, int type
, int verbose
)
135 * Read a contract event.
137 if (errno
= ct_event_read(fd
, &ev
)) {
140 uu_die(gettext("could not receive contract event"));
144 * Emit a one-line event summary.
146 flags
= ct_event_get_flags(ev
);
147 (void) printf("%-8ld%-8lld%-5s%-4s%-9s",
148 ct_event_get_ctid(ev
),
149 ct_event_get_evid(ev
),
150 (flags
& CTE_INFO
) ? "info" : (flags
& CTE_NEG
) ? "neg" : "crit",
151 flags
& CTE_ACK
? "yes" : "no",
155 * Display event details, if requested.
156 * (Since this is also needed by ctrun, the common
157 * contract_event_dump is found in libcontract.)
159 contract_event_dump(stdout
, ev
, verbose
);
168 * Given a contract type name, return an index into the 'types' array.
172 get_type(const char *typestr
)
175 for (i
= 0; types
[i
].name
; i
++)
176 if (strcmp(types
[i
].name
, typestr
) == 0)
178 uu_die(gettext("invalid contract type: %s\n"), typestr
);
185 * Given a contract id, return an index into the 'types' array.
186 * Returns -1 on failure.
189 contract_type(ctid_t id
)
195 * This could be faster (e.g. by reading the link itself), but
196 * this is the most straightforward implementation.
198 if ((fd
= contract_open(id
, NULL
, "status", O_RDONLY
)) == -1)
200 if (errno
= ct_status_read(fd
, CTD_COMMON
, &hdl
)) {
204 type
= get_type(ct_status_get_type(hdl
));
213 * A simple contract ID comparator.
216 ctid_compar(const void *a1
, const void *a2
)
218 ctid_t id1
= *(ctid_t
*)a1
;
219 ctid_t id2
= *(ctid_t
*)a2
;
229 main(int argc
, char **argv
)
231 int opt_reliable
= 0;
239 (void) setlocale(LC_ALL
, "");
240 (void) textdomain(TEXT_DOMAIN
);
242 (void) uu_setpname(argv
[0]);
244 while ((i
= getopt(argc
, argv
, "rfv")) != EOF
) {
266 wfd
= calloc(argc
, sizeof (struct pollfd
));
269 ids
= calloc(argc
, sizeof (ctid_t
));
274 * Scan our operands for contract ids and types.
278 for (i
= 0; i
< argc
; i
++) {
280 if (strchr(argv
[i
], '/') != NULL
)
281 uu_die(gettext("invalid contract type: %s\n"), argv
[i
]);
284 * If argument isn't a number between 0 and INT_MAX,
285 * treat it as a contract type.
287 if (uu_strtoint(argv
[i
], &id
, sizeof (id
), 10, 1, INT_MAX
)) {
290 sopen(CTFS_ROOT
"/%s/bundle",
291 gettext("invalid contract type: %s\n"), NULL
,
293 wfd
[nfds
].wf_type
= type
= get_type(argv
[i
]);
294 if (types
[type
].found
) {
295 (void) close(wfd
[nfds
].wf_fd
);
298 types
[type
].found
= 1;
306 * Eliminate those contract ids which are represented by
307 * contract types, so we don't get duplicate event reports from
310 * Sorting the array first allows us to efficiently skip
311 * duplicate ids. We know that the array only contains
312 * integers [0, INT_MAX].
314 qsort(ids
, nids
, sizeof (ctid_t
), ctid_compar
);
316 for (i
= 0; i
< nids
; i
++) {
323 fd
= sopen(CTFS_ROOT
"/all/%d/events",
324 gettext("invalid contract id: %d\n"),
325 gettext("could not access contract id %d\n"), ids
[i
]);
328 if ((type
= contract_type(ids
[i
])) == -1) {
330 uu_warn(gettext("could not access contract id %d\n"),
334 if (types
[type
].found
) {
338 wfd
[nfds
].wf_fd
= fd
;
339 wfd
[nfds
].wf_type
= type
;
345 uu_die(gettext("no contracts to watch\n"));
351 for (i
= 0; i
< nfds
; i
++)
352 if (ioctl(wfd
[i
].wf_fd
, CT_ERELIABLE
, NULL
) == -1) {
353 uu_warn("could not request reliable events");
358 for (i
= 0; i
< nfds
; i
++)
359 (void) ioctl(wfd
[i
].wf_fd
, CT_ERESET
, NULL
);
363 * Allocate an event point, and associate all our endpoint file
364 * descriptors with it.
366 if ((port_fd
= port_create()) == -1)
368 for (i
= 0; i
< nfds
; i
++)
369 if (port_associate(port_fd
, PORT_SOURCE_FD
, wfd
[i
].wf_fd
,
370 POLLIN
, &wfd
[i
]) == -1)
374 * Loop waiting for and displaying events.
380 if (port_get(port_fd
, &pe
, NULL
) == -1) {
386 while (get_event(pe
.portev_object
, w
->wf_type
, opt_verbose
))
388 if (port_associate(port_fd
, PORT_SOURCE_FD
, pe
.portev_object
,
389 POLLIN
, pe
.portev_user
) == -1)
394 uu_die(gettext("error waiting for contract events"));
396 return (1); /* placate cc */