Home | History | Annotate | Download | only in ctrun
      1 /*
      2  * CDDL HEADER START
      3  *
      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.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/types.h>
     29 #include <sys/wait.h>
     30 #include <sys/ctfs.h>
     31 #include <sys/contract.h>
     32 #include <sys/contract/process.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <unistd.h>
     36 #include <fcntl.h>
     37 #include <string.h>
     38 #include <errno.h>
     39 #include <signal.h>
     40 #include <limits.h>
     41 #include <libuutil.h>
     42 #include <libcontract.h>
     43 #include <libcontract_priv.h>
     44 
     45 #include <locale.h>
     46 #include <langinfo.h>
     47 
     48 static int opt_verbose;
     49 static int opt_Verbose;
     50 
     51 #define	OPT_NORMAL	0x1
     52 #define	OPT_FATAL	0x2
     53 
     54 typedef struct optvect {
     55 	const char	*opt_name;
     56 	uint_t		opt_value;
     57 	uint_t		opt_flags;
     58 } optvect_t;
     59 
     60 static optvect_t option_params[] = {
     61 	{ "noorphan", CT_PR_NOORPHAN },
     62 	{ "pgrponly", CT_PR_PGRPONLY },
     63 	{ "regent", CT_PR_REGENT },
     64 	{ "inherit", CT_PR_INHERIT },
     65 	{ NULL }
     66 };
     67 
     68 static optvect_t option_events[] = {
     69 	{ "core", CT_PR_EV_CORE, OPT_NORMAL | OPT_FATAL },
     70 	{ "signal", CT_PR_EV_SIGNAL, OPT_NORMAL | OPT_FATAL },
     71 	{ "hwerr", CT_PR_EV_HWERR, OPT_NORMAL | OPT_FATAL },
     72 	{ "empty", CT_PR_EV_EMPTY, OPT_NORMAL },
     73 	{ "fork", CT_PR_EV_FORK, OPT_NORMAL },
     74 	{ "exit", CT_PR_EV_EXIT, OPT_NORMAL },
     75 	{ NULL }
     76 };
     77 
     78 typedef enum lifetime {
     79 	LT_NONE,
     80 	LT_CHILD,
     81 	LT_CONTRACT
     82 } lifetime_t;
     83 
     84 /*
     85  * Exit code to use when the child exited abnormally (i.e. exited with
     86  * a status we are unable to emulate).
     87  */
     88 #define	EXIT_BADCHILD	123
     89 
     90 #define	USAGESTR	\
     91 	"Usage: %s [-i eventlist] [-f eventlist] [-l lifetime] \n" \
     92 	"\t[-o optionlist] [-r count [-t]] [-v]\n" \
     93 	"\t[-F fmri] [-A aux] command\n"
     94 
     95 /*
     96  * usage
     97  *
     98  * Educate the user.
     99  */
    100 static void
    101 usage(void)
    102 {
    103 	(void) fprintf(stderr, gettext(USAGESTR), uu_getpname());
    104 	exit(UU_EXIT_USAGE);
    105 }
    106 
    107 /*
    108  * bit2str
    109  *
    110  * Convert a bit into its string representation.
    111  */
    112 static const char *
    113 bit2str(optvect_t *options, uint_t bit)
    114 {
    115 	for (; options->opt_name; options++)
    116 		if (options->opt_value == bit)
    117 			return (options->opt_name);
    118 	return (NULL);
    119 }
    120 
    121 /*
    122  * str2bit
    123  *
    124  * Convert a string into its bit representation.  If match is set, only
    125  * look at those options with the match bit set in its opt_flags
    126  * field.
    127  */
    128 static uint_t
    129 str2bit(optvect_t *options, int match, const char *str, int len)
    130 {
    131 	for (; options->opt_name; options++) {
    132 		if (match && (options->opt_flags & match) == 0)
    133 			continue;
    134 		if (strncmp(str, options->opt_name, len) == 0)
    135 			return (options->opt_value);
    136 	}
    137 	return (0);
    138 }
    139 
    140 /*
    141  * opt2bits
    142  *
    143  * Given a set of textual options separated by commas or spaces,
    144  * convert them to a set of bits.  Errors are fatal, except for empty
    145  * options (which are ignored) and duplicate options (which are
    146  * idempotent).
    147  */
    148 static void
    149 opt2bits(optvect_t *options, int match, const char *str, uint_t *bits, char c)
    150 {
    151 	const char *ptr, *next = str;
    152 	uint_t result = 0;
    153 	uint_t bit;
    154 	int none = 0;
    155 
    156 	while (*str) {
    157 		int len;
    158 
    159 		ptr = strpbrk(str, ", ");
    160 		if (ptr != NULL) {
    161 			len = ptr - str;
    162 			next = ptr + 1;
    163 		} else {
    164 			len = strlen(str);
    165 			next = str + len;
    166 		}
    167 		if (len == 0) {
    168 			uu_warn(gettext("empty option\n"));
    169 			bit = 0;
    170 		} else {
    171 			bit = str2bit(options, match, str, len);
    172 			if (bit == 0 && strncmp(str, "none", len) == 0) {
    173 				none = 1;
    174 				if (result)
    175 					goto noneerr;
    176 			} else if (bit == 0) {
    177 				uu_warn(gettext("unrecognized option '%.*s'\n"),
    178 				    len, str);
    179 				uu_warn(gettext("error parsing '-%c' option\n"),
    180 				    c);
    181 				usage();
    182 			} else if (none) {
    183 				goto noneerr;
    184 			}
    185 			if (result & bit)
    186 				uu_warn(gettext("option '%.*s' "
    187 				    "specified twice\n"), len, str);
    188 		}
    189 		result |= bit;
    190 		str = next;
    191 	}
    192 
    193 	*bits = result;
    194 	return;
    195 
    196 noneerr:
    197 	uu_warn(gettext("option is incompatible with others: '%s'\n"), "none");
    198 	usage();
    199 }
    200 
    201 /*
    202  * close_on_exec
    203  *
    204  * Given a fd, marks it close-on-exec.
    205  */
    206 static int
    207 close_on_exec(int fd)
    208 {
    209 	int flags = fcntl(fd, F_GETFD, 0);
    210 	if ((flags != -1) && (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1))
    211 		return (0);
    212 	return (-1);
    213 }
    214 
    215 /*
    216  * v_printf
    217  *
    218  * Output routine for messages printed only when -v is specified.
    219  */
    220 /* PRINTFLIKE1 */
    221 static void
    222 v_printf(const char *format, ...)
    223 {
    224 	va_list va;
    225 
    226 	if (opt_verbose) {
    227 		(void) printf("%s(%ld): ", uu_getpname(), getpid());
    228 		va_start(va, format);
    229 		(void) vprintf(format, va);
    230 		va_end(va);
    231 	}
    232 }
    233 
    234 /*
    235  * get_event
    236  *
    237  * Reads and acknowledges an event.  Returns the event type.
    238  */
    239 static uint_t
    240 get_event(int fd, int ctfd, ctid_t ctid)
    241 {
    242 	ct_evthdl_t ev;
    243 	uint_t result;
    244 	ctevid_t evid;
    245 
    246 	for (;;) {
    247 		int efd;
    248 
    249 		/*
    250 		 * Normally we only need to look at critical messages.
    251 		 * If we are displaying contract events, however, we
    252 		 * have to read them all.
    253 		 */
    254 		errno = opt_verbose ? ct_event_read(fd, &ev) :
    255 		    ct_event_read_critical(fd, &ev);
    256 		if (errno != 0)
    257 			uu_die(gettext("failed to listen to contract events"));
    258 
    259 		/*
    260 		 * If requested, display the event.
    261 		 */
    262 		if (opt_verbose) {
    263 			v_printf(gettext("event from contract %ld: "),
    264 			    ct_event_get_ctid(ev));
    265 			contract_event_dump(stdout, ev, opt_Verbose);
    266 			if ((ct_event_get_flags(ev) & CTE_INFO) != 0) {
    267 				ct_event_free(ev);
    268 				continue;
    269 			}
    270 		}
    271 
    272 		/*
    273 		 * We're done if this event is one of ours.
    274 		 */
    275 		evid = ct_event_get_evid(ev);
    276 		if (ct_event_get_ctid(ev) == ctid)
    277 			break;
    278 
    279 		/*
    280 		 * ACK events from other contracts.
    281 		 * This shouldn't happen, but it could.
    282 		 */
    283 		efd = contract_open(ct_event_get_ctid(ev), "process", "ctl",
    284 		    O_WRONLY);
    285 		if (efd != -1) {
    286 			(void) ct_ctl_ack(efd, evid);
    287 			(void) close(efd);
    288 		}
    289 		ct_event_free(ev);
    290 	}
    291 
    292 	/*
    293 	 * Note that if we want to use ctrun as a simple restarter, we
    294 	 * need persistently keep track of fatal events so we can
    295 	 * properly handle the death of the contract.  Rather than keep
    296 	 * a file or somesuch lying around, it might make more sense to
    297 	 * leave the significant fatal event sitting in the queue so
    298 	 * that a restarted instance of ctrun can pick it up.  For now
    299 	 * we'll just ACK all events.
    300 	 */
    301 	(void) ct_ctl_ack(ctfd, evid);
    302 
    303 	result = ct_event_get_type(ev);
    304 	ct_event_free(ev);
    305 
    306 	return (result);
    307 }
    308 
    309 /*
    310  * abandon
    311  *
    312  * Given an fd for a contract's ctl file, abandon the contract and
    313  * close the file.
    314  */
    315 static void
    316 abandon(int ctfd)
    317 {
    318 	if (ct_ctl_abandon(ctfd) == -1)
    319 		uu_die(gettext("failed to abandon contract %d"), ctfd);
    320 
    321 	(void) close(ctfd);
    322 }
    323 
    324 static int chldstat;
    325 static int chldexited;
    326 
    327 /*
    328  * sigchld
    329  *
    330  * Our SIGCHLD handler.  Sets chldstat and chldexited so the
    331  * interrupted code knows what happened.
    332  */
    333 /*ARGSUSED*/
    334 static void
    335 sigchld(int sig, struct siginfo *si, void *ucp)
    336 {
    337 	int err = errno;
    338 
    339 	if (si->si_code == CLD_EXITED)
    340 		chldstat = si->si_status;
    341 	else
    342 		chldstat = EXIT_BADCHILD;
    343 	chldexited = 1;
    344 	while (waitpid(si->si_pid, NULL, 0) == -1 && errno == EINTR)
    345 		;
    346 	errno = err;
    347 }
    348 
    349 /*
    350  * dowait
    351  *
    352  * Waits for the specified child to exit.  Returns the exit code ctrun
    353  * should return.
    354  */
    355 static int
    356 dowait(int pid)
    357 {
    358 	pid_t wpid;
    359 	int wstatus;
    360 
    361 	do
    362 		wpid = waitpid(pid, &wstatus, 0);
    363 	while (wpid == -1 && errno == EINTR);
    364 
    365 	if (wpid == -1)
    366 		uu_die(gettext("wait failed"));
    367 
    368 	if (WIFEXITED(wstatus))
    369 		return (WEXITSTATUS(wstatus));
    370 	else
    371 		return (EXIT_BADCHILD);
    372 }
    373 
    374 int
    375 main(int argc, char **argv)
    376 {
    377 	int	fd, efd;
    378 	pid_t	pid;
    379 	ctid_t	ctid = 0;
    380 	int	ctfd;
    381 	int	pipefds[2];
    382 	struct sigaction osact;
    383 
    384 	int	s;
    385 	ctid_t	opt_adopt = 0;
    386 	int	opt_transfer = 0;
    387 	int	opt_count = -1;
    388 	uint_t	opt_info = CT_PR_EV_CORE;
    389 	uint_t	opt_crit = 0;
    390 	uint_t	eff_fatal, opt_fatal = CT_PR_EV_HWERR;
    391 	uint_t	eff_param, opt_param = 0;
    392 	lifetime_t opt_life = LT_CONTRACT;
    393 
    394 	char *svc_fmri = NULL;
    395 	char *svc_aux = NULL;
    396 
    397 	(void) setlocale(LC_ALL, "");
    398 	(void) textdomain(TEXT_DOMAIN);
    399 	uu_alt_exit(UU_PROFILE_LAUNCHER);
    400 
    401 	(void) uu_setpname(argv[0]);
    402 
    403 	while ((s = getopt(argc, argv, "a:A:l:o:i:c:f:F:r:tvV")) != EOF) {
    404 		switch (s) {
    405 		case 'a':
    406 			if (uu_strtoint(optarg, &opt_adopt, sizeof (opt_adopt),
    407 			    0, 0, INT32_MAX) == -1) {
    408 				uu_warn(gettext("invalid contract ID '%s'\n"),
    409 				    optarg);
    410 				usage();
    411 			}
    412 			break;
    413 		case 'v':
    414 			opt_verbose = 1;
    415 			break;
    416 		case 'V':
    417 			opt_Verbose = 1;
    418 			opt_verbose = 1;
    419 			break;
    420 		case 't':
    421 			opt_transfer = 1;
    422 			break;
    423 		case 'r':
    424 			if (uu_strtoint(optarg, &opt_count, sizeof (opt_adopt),
    425 			    0, 0, INT32_MAX) == -1) {
    426 				uu_warn(gettext("invalid count '%s'\n"),
    427 				    optarg);
    428 				usage();
    429 			}
    430 			break;
    431 		case 'l':
    432 			if (strcmp(optarg, "none") == 0) {
    433 				opt_life = LT_NONE;
    434 			} else if (strcmp(optarg, "child") == 0) {
    435 				opt_life = LT_CHILD;
    436 			} else if (strcmp(optarg, "contract") == 0) {
    437 				opt_life = LT_CONTRACT;
    438 			} else {
    439 				uu_warn(gettext("invalid lifetime '%s'\n"),
    440 				    optarg);
    441 				usage();
    442 			}
    443 
    444 			break;
    445 		case 'o':
    446 			opt2bits(option_params, 0, optarg, &opt_param,
    447 			    optopt);
    448 			break;
    449 		case 'i':
    450 			opt2bits(option_events, OPT_NORMAL, optarg, &opt_info,
    451 			    optopt);
    452 			break;
    453 		case 'c':
    454 			opt2bits(option_events, OPT_NORMAL, optarg, &opt_crit,
    455 			    optopt);
    456 			break;
    457 		case 'f':
    458 			opt2bits(option_events, OPT_FATAL, optarg, &opt_fatal,
    459 			    optopt);
    460 			break;
    461 		case 'F':
    462 			svc_fmri = optarg;
    463 			break;
    464 		case 'A':
    465 			svc_aux = optarg;
    466 			break;
    467 		default:
    468 			usage();
    469 		}
    470 	}
    471 	argc -= optind;
    472 	argv += optind;
    473 
    474 	/*
    475 	 * Basic argument sanity checks.
    476 	 */
    477 	if ((opt_life == LT_NONE) && (opt_param & CT_PR_NOORPHAN)) {
    478 		uu_warn(gettext("cannot use option '%s' with lifetime '%s'\n"),
    479 		    bit2str(option_params, CT_PR_NOORPHAN), "none");
    480 		usage();
    481 	}
    482 
    483 	if ((opt_life != LT_CONTRACT) && (opt_count >= 0)) {
    484 		uu_warn(gettext("cannot restart with lifetime '%s'\n"),
    485 		    opt_life == LT_NONE ? "none" : "child");
    486 		usage();
    487 	}
    488 
    489 	if ((opt_param & CT_PR_PGRPONLY) && (opt_count >= 0)) {
    490 		uu_warn(gettext("cannot restart with option '%s'\n"),
    491 		    bit2str(option_params, CT_PR_PGRPONLY));
    492 		usage();
    493 	}
    494 
    495 	if (opt_transfer && (opt_count == -1)) {
    496 		uu_warn(gettext("cannot transfer when not restarting\n"));
    497 		usage();
    498 	}
    499 
    500 	if (argc <= 0)
    501 		usage();
    502 
    503 	/*
    504 	 * Create a process contract template and our process's process
    505 	 * contract bundle endpoint.  Mark them close-on-exec so we
    506 	 * don't have to worry about closing them in our child.
    507 	 */
    508 	fd = open64(CTFS_ROOT "/process/template", O_RDWR);
    509 	if (fd == -1)
    510 		uu_die(gettext("template open failed"));
    511 
    512 	efd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY);
    513 	if (efd == -1)
    514 		uu_die(gettext("process bundle open failed"));
    515 
    516 	if (close_on_exec(fd) || close_on_exec(efd))
    517 		uu_die(gettext("could not set FD_CLOEXEC"));
    518 
    519 	/*
    520 	 * Set the process contract's terms based on our arguments.
    521 	 */
    522 	if (errno = ct_pr_tmpl_set_param(fd, opt_param))
    523 		uu_die(gettext("set param failed"));
    524 
    525 	if (errno = ct_tmpl_set_informative(fd, opt_info))
    526 		uu_die(gettext("set notify failed"));
    527 
    528 	if (errno = ct_pr_tmpl_set_fatal(fd, opt_fatal))
    529 		uu_die(gettext("set fatal failed"));
    530 
    531 	if (opt_param & CT_PR_PGRPONLY)
    532 		opt_crit = CT_PR_EV_EMPTY;
    533 	else
    534 		opt_crit |= opt_fatal | CT_PR_EV_EMPTY;
    535 	if (errno = ct_tmpl_set_critical(fd, opt_crit))
    536 		uu_die(gettext("set critical failed"));
    537 	if (svc_fmri && (errno = ct_pr_tmpl_set_svc_fmri(fd, svc_fmri)))
    538 		uu_die(gettext("set fmri failed: "
    539 		    "insufficient privileges\n"));
    540 	if (svc_aux && (errno = ct_pr_tmpl_set_svc_aux(fd, svc_aux)))
    541 		uu_die(gettext("set aux failed"));
    542 
    543 	/*
    544 	 * Activate the template.
    545 	 */
    546 	if (errno = ct_tmpl_activate(fd))
    547 		uu_die(gettext("template activate failed"));
    548 
    549 restart:
    550 	if (opt_adopt) {
    551 		/*
    552 		 * Adopt a specific contract.
    553 		 */
    554 		ct_stathdl_t st;
    555 		int stfd;
    556 
    557 		if ((ctfd = contract_open(opt_adopt, "process", "ctl",
    558 		    O_WRONLY)) == -1)
    559 			uu_die(gettext("could not open contract %ld"),
    560 			    opt_adopt);
    561 
    562 		/*
    563 		 * Read the contract's terms so that we interpret its
    564 		 * events properly.
    565 		 */
    566 		if (((stfd = contract_open(opt_adopt, "process", "status",
    567 		    O_RDONLY)) == -1) ||
    568 		    (errno = ct_status_read(stfd, CTD_FIXED, &st)) ||
    569 		    (errno = ct_pr_status_get_fatal(st, &eff_fatal)) ||
    570 		    (errno = ct_pr_status_get_param(st, &eff_param)))
    571 			uu_die(gettext("could not stat contract %ld"),
    572 			    opt_adopt);
    573 		ct_status_free(st);
    574 		(void) close(stfd);
    575 
    576 		if (errno = ct_ctl_adopt(ctfd))
    577 			uu_die(gettext("could not adopt contract %ld"),
    578 			    opt_adopt);
    579 
    580 		ctid = opt_adopt;
    581 		opt_adopt = 0;
    582 		v_printf(gettext("adopted contract id %ld\n"), ctid);
    583 	} else {
    584 		/*
    585 		 * Create a new process.
    586 		 */
    587 		if (opt_life == LT_CONTRACT) {
    588 			struct sigaction sact;
    589 
    590 			/*
    591 			 * Since we are going to be waiting for and
    592 			 * reacting to contract events, install a
    593 			 * signal handler so we capture the exit status
    594 			 * of our child.
    595 			 */
    596 			chldstat = UU_EXIT_OK;
    597 			chldexited = 0;
    598 			sact.sa_sigaction = sigchld;
    599 			sact.sa_flags = SA_SIGINFO | SA_RESTART |
    600 			    SA_NOCLDSTOP;
    601 			(void) sigemptyset(&sact.sa_mask);
    602 			if (sigaction(SIGCHLD, &sact, &osact) == -1)
    603 				uu_die(gettext("failed to install "
    604 				    "sigchld handler"));
    605 		} else if (opt_life == LT_NONE) {
    606 			/*
    607 			 * Though we aren't waiting for our child to
    608 			 * exit, as a well-behaved command launcher we
    609 			 * must wait for it to exec.  On success the
    610 			 * pipe will simply close, and on failure the
    611 			 * proper exit status will be sent.
    612 			 */
    613 			if (pipe(pipefds) == -1 ||
    614 			    close_on_exec(pipefds[0]) == -1 ||
    615 			    close_on_exec(pipefds[1]) == -1)
    616 				uu_die(gettext("failed to create pipe"));
    617 		}
    618 
    619 		if ((pid = fork()) == -1) {
    620 			uu_die(gettext("fork failed"));
    621 		} else if (pid == 0) {
    622 			int result = execvp(argv[0], argv);
    623 			if (opt_life == LT_NONE) {
    624 				char a = 1;
    625 				int err = errno;
    626 
    627 				(void) write(pipefds[1], &a, sizeof (a));
    628 				errno = err;
    629 			}
    630 			if (result == -1)
    631 				uu_xdie(errno == ENOENT ? 127 : 126,
    632 				    gettext("exec failed"));
    633 			uu_die(gettext("exec returned!\n"));
    634 		}
    635 
    636 		/*
    637 		 * Get the newly-created contract's id and ctl fd.
    638 		 */
    639 		if (errno = contract_latest(&ctid))
    640 			uu_die(gettext("could not get new contract's id"));
    641 		if ((ctfd = contract_open(ctid, "process", "ctl",
    642 		    O_WRONLY)) == -1)
    643 			uu_die(gettext("could not open contract"));
    644 
    645 		/*
    646 		 * Clear the transfer parameter so that the contract
    647 		 * will be freed sooner and admins won't get nervous.
    648 		 */
    649 		if (opt_transfer) {
    650 			(void) ct_pr_tmpl_set_transfer(fd, 0);
    651 			(void) ct_tmpl_activate(fd);
    652 		}
    653 
    654 		v_printf(gettext("created contract id %ld\n"), ctid);
    655 		eff_param = opt_param;
    656 		eff_fatal = opt_fatal;
    657 	}
    658 
    659 	if (opt_life == LT_CONTRACT) {
    660 		uint_t event, errevent = 0;
    661 
    662 		/*
    663 		 * Wait until the contract empties out.
    664 		 */
    665 		do {
    666 			event = get_event(efd, ctfd, ctid);
    667 			if (event & eff_fatal) {
    668 				if ((eff_param & CT_PR_PGRPONLY) == 0)
    669 					errevent = event;
    670 				v_printf(gettext(
    671 				    "fatal \"%s\" event from contract %ld\n"),
    672 				    bit2str(option_events, event), ctid);
    673 			}
    674 		} while ((event & CT_PR_EV_EMPTY) == 0);
    675 
    676 		/*
    677 		 * If we encountered a fatal error event, and we
    678 		 * haven't expended our maximum loop count, restart.
    679 		 */
    680 		if ((errevent != 0) &&
    681 		    ((opt_count == 0) || (opt_count-- > 1))) {
    682 			v_printf(gettext("failure in contract %ld, "
    683 			    "restarting command\n"), ctid);
    684 			if (opt_transfer) {
    685 				/*
    686 				 * Add the failed contract to the new
    687 				 * contract's terms so that its
    688 				 * inherited subcontracts can be
    689 				 * adopted by the new process.
    690 				 */
    691 				if (errno = ct_pr_tmpl_set_transfer(fd, ctid))
    692 					uu_die(gettext("set transfer failed"));
    693 				if (errno = ct_tmpl_activate(fd))
    694 					uu_die(gettext(
    695 					    "template activate failed"));
    696 				(void) close(ctfd);
    697 			} else {
    698 				abandon(ctfd);
    699 			}
    700 			goto restart;
    701 		}
    702 
    703 		/*
    704 		 * At this point we are done with the contract; we
    705 		 * don't want it to be inherited when we exit.
    706 		 */
    707 		abandon(ctfd);
    708 
    709 		/*
    710 		 * In case there was a race between SIGCHLD delivery
    711 		 * and contract event delivery, disable the signal
    712 		 * handler and look for the child.
    713 		 */
    714 		(void) sigaction(SIGCHLD, &osact, NULL);
    715 		if (chldexited == 0)
    716 			chldstat = dowait(pid);
    717 	} else if (opt_life == LT_NONE) {
    718 		char a;
    719 		int result;
    720 
    721 		chldstat = UU_EXIT_OK;
    722 		(void) close(pipefds[1]);
    723 		do {
    724 			result = read(pipefds[0], &a, sizeof (a));
    725 			if (result == -1 && errno != EINTR)
    726 				uu_die(gettext("read failed"));
    727 			if (result == 1)
    728 				chldstat = dowait(pid);
    729 		} while (result == -1);
    730 	} else {
    731 		chldstat = dowait(pid);
    732 	}
    733 
    734 	return (chldstat);
    735 }
    736