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 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 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 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 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