xref: /illumos-gate/usr/src/lib/libproc/common/proc_stdio.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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 /*
28  * Utility functions for buffering output to stdout, stderr while
29  * process is grabbed.  Prevents infamous deadlocks due to pfiles `pgrep xterm`
30  * and other varients.
31  */
32 
33 #include "libproc.h"
34 #include <stdio.h>
35 
36 static int cached_stdout_fd = -1;
37 static int cached_stderr_fd = -1;
38 static int initialized = 0;
39 
40 static char stdout_name[] = "/tmp/.stdoutXXXXXX";
41 static char stderr_name[] = "/tmp/.stderrXXXXXX";
42 
43 int
proc_initstdio(void)44 proc_initstdio(void)
45 {
46 	int fd;
47 
48 	(void) fflush(stdout);
49 	(void) fflush(stderr);
50 
51 	if ((cached_stdout_fd = dup(1)) < 0) {
52 		return (-1);
53 	}
54 
55 	if ((cached_stderr_fd = dup(2)) < 0) {
56 		(void) close(cached_stdout_fd);
57 		return (-1);
58 	}
59 
60 	if ((fd = mkstemp(stdout_name)) < 0) {
61 		(void) close(cached_stdout_fd);
62 		(void) close(cached_stderr_fd);
63 		return (-1);
64 	}
65 
66 	(void) unlink(stdout_name);
67 
68 	if (dup2(fd, 1) < 0) {
69 		(void) close(fd);
70 		(void) close(cached_stdout_fd);
71 		(void) close(cached_stderr_fd);
72 		return (-1);
73 	}
74 
75 	(void) close(fd);
76 
77 
78 	if ((fd = mkstemp(stderr_name)) < 0) {
79 		(void) dup2(cached_stdout_fd, 1);
80 		(void) close(cached_stdout_fd);
81 		(void) close(cached_stderr_fd);
82 		return (-1);
83 	}
84 
85 	(void) unlink(stderr_name);
86 
87 	if (dup2(fd, 2) < 0) {
88 		(void) close(fd);
89 		(void) dup2(cached_stdout_fd, 1);
90 		(void) close(cached_stdout_fd);
91 		(void) dup2(cached_stderr_fd, 2);
92 		(void) close(cached_stderr_fd);
93 		(void) close(fd);
94 		return (-1);
95 	}
96 
97 	(void) close(fd);
98 
99 	initialized = 1;
100 
101 	return (0);
102 }
103 
104 static int
copy_fd(int out,FILE * in,size_t len)105 copy_fd(int out, FILE *in, size_t len)
106 {
107 	char buffer[8192];
108 	int rlen, alen;
109 	int errors = 0;
110 
111 	rewind(in);
112 	while (len > 0 && !errors) {
113 		rlen = (len > sizeof (buffer)) ? sizeof (buffer) : len;
114 		alen = read(fileno(in), buffer, rlen);
115 		if (alen == rlen) {
116 			if (write(out, buffer, alen) < alen)
117 				errors++;
118 			else
119 				len -= alen;
120 		}
121 		else
122 			errors++;
123 	}
124 	rewind(in);
125 	return (errors);
126 }
127 
128 int
proc_flushstdio(void)129 proc_flushstdio(void)
130 {
131 	size_t len;
132 	int errors = 0;
133 
134 	/*
135 	 * flush any pending IO
136 	 */
137 
138 	if (!initialized)
139 		return (-1);
140 
141 	(void) fflush(stdout);
142 	(void) fflush(stderr);
143 
144 	if ((len = ftell(stdout)) > 0)
145 		errors += copy_fd(cached_stdout_fd, stdout, len);
146 
147 
148 	if ((len = ftell(stderr)) > 0)
149 		errors += copy_fd(cached_stderr_fd, stderr, len);
150 
151 	return (errors?-1:0);
152 }
153 
154 int
proc_finistdio(void)155 proc_finistdio(void)
156 {
157 	if (!initialized)
158 		return (-1);
159 
160 	if (proc_flushstdio() != 0)
161 		return (-1);
162 
163 	(void) dup2(cached_stdout_fd, 1);
164 	(void) close(cached_stdout_fd);
165 	(void) dup2(cached_stderr_fd, 2);
166 	(void) close(cached_stderr_fd);
167 
168 	return (0);
169 }
170