Home | History | Annotate | Download | only in common
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * Utility functions for buffering output to stdout, stderr while
     31  * process is grabbed.  Prevents infamous deadlocks due to pfiles `pgrep xterm`
     32  * and other varients.
     33  */
     34 
     35 #include "libproc.h"
     36 #include <stdio.h>
     37 
     38 static int cached_stdout_fd = -1;
     39 static int cached_stderr_fd = -1;
     40 static int initialized = 0;
     41 
     42 static char stdout_name[] = "/tmp/.stdoutXXXXXX";
     43 static char stderr_name[] = "/tmp/.stderrXXXXXX";
     44 
     45 int
     46 proc_initstdio(void)
     47 {
     48 	int fd;
     49 
     50 	(void) fflush(stdout);
     51 	(void) fflush(stderr);
     52 
     53 	if ((cached_stdout_fd = dup(1)) < 0) {
     54 		return (-1);
     55 	}
     56 
     57 	if ((cached_stderr_fd = dup(2)) < 0) {
     58 		(void) close(cached_stdout_fd);
     59 		return (-1);
     60 	}
     61 
     62 	if ((fd = mkstemp(stdout_name)) < 0) {
     63 		(void) close(cached_stdout_fd);
     64 		(void) close(cached_stderr_fd);
     65 		return (-1);
     66 	}
     67 
     68 	(void) unlink(stdout_name);
     69 
     70 	if (dup2(fd, 1) < 0) {
     71 		(void) close(fd);
     72 		(void) close(cached_stdout_fd);
     73 		(void) close(cached_stderr_fd);
     74 		return (-1);
     75 	}
     76 
     77 	(void) close(fd);
     78 
     79 
     80 	if ((fd = mkstemp(stderr_name)) < 0) {
     81 		(void) dup2(cached_stdout_fd, 1);
     82 		(void) close(cached_stdout_fd);
     83 		(void) close(cached_stderr_fd);
     84 		return (-1);
     85 	}
     86 
     87 	(void) unlink(stderr_name);
     88 
     89 	if (dup2(fd, 2) < 0) {
     90 		(void) close(fd);
     91 		(void) dup2(cached_stdout_fd, 1);
     92 		(void) close(cached_stdout_fd);
     93 		(void) dup2(cached_stderr_fd, 2);
     94 		(void) close(cached_stderr_fd);
     95 		(void) close(fd);
     96 		return (-1);
     97 	}
     98 
     99 	(void) close(fd);
    100 
    101 	initialized = 1;
    102 
    103 	return (0);
    104 }
    105 
    106 static int
    107 copy_fd(int out, FILE *in, size_t len)
    108 {
    109 	char buffer[8192];
    110 	int rlen, alen;
    111 	int errors = 0;
    112 
    113 	rewind(in);
    114 	while (len > 0 && !errors) {
    115 		rlen = (len > sizeof (buffer)) ? sizeof (buffer) : len;
    116 		alen = read(fileno(in), buffer, rlen);
    117 		if (alen == rlen) {
    118 			if (write(out, buffer, alen) < alen)
    119 				errors++;
    120 			else
    121 				len -= alen;
    122 		}
    123 		else
    124 			errors++;
    125 	}
    126 	rewind(in);
    127 	return (errors);
    128 }
    129 
    130 int
    131 proc_flushstdio(void)
    132 {
    133 	size_t len;
    134 	int errors = 0;
    135 
    136 	/*
    137 	 * flush any pending IO
    138 	 */
    139 
    140 	if (!initialized)
    141 		return (-1);
    142 
    143 	(void) fflush(stdout);
    144 	(void) fflush(stderr);
    145 
    146 	if ((len = ftell(stdout)) > 0)
    147 		errors += copy_fd(cached_stdout_fd, stdout, len);
    148 
    149 
    150 	if ((len = ftell(stderr)) > 0)
    151 		errors += copy_fd(cached_stderr_fd, stderr, len);
    152 
    153 	return (errors?-1:0);
    154 }
    155 
    156 int
    157 proc_finistdio(void)
    158 {
    159 	if (!initialized)
    160 		return (-1);
    161 
    162 	if (proc_flushstdio() != 0)
    163 		return (-1);
    164 
    165 	(void) dup2(cached_stdout_fd, 1);
    166 	(void) close(cached_stdout_fd);
    167 	(void) dup2(cached_stderr_fd, 2);
    168 	(void) close(cached_stderr_fd);
    169 
    170 	return (0);
    171 }
    172