Imported Upstream version 15.8a
[platform/upstream/cscope.git] / src / mypopen.c
1 /*===========================================================================
2  Copyright (c) 1998-2000, The Santa Cruz Operation 
3  All rights reserved.
4  
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7
8  *Redistributions of source code must retain the above copyright notice,
9  this list of conditions and the following disclaimer.
10
11  *Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14
15  *Neither name of The Santa Cruz Operation nor the names of its contributors
16  may be used to endorse or promote products derived from this software
17  without specific prior written permission. 
18
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
20  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
23  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  INTERRUPTION)
27  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  DAMAGE. 
31  =========================================================================*/
32
33 #include <stdio.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include "global.h"     /* pid_t, RETSIGTYPE, shell, and mybasename() */
39
40 #define tst(a,b) (*mode == 'r'? (b) : (a))
41 #define RDR     0
42 #define WTR     1
43
44 /* HBB 20010312: make this a bit safer --- don't blindly assume it's 1 */
45 #ifdef FD_CLOEXEC
46 # define CLOSE_ON_EXEC FD_CLOEXEC
47 #else
48 # define CLOSE_ON_EXEC 1
49 #endif
50
51 #ifdef HAVE_IO_H
52 # include <io.h>                /* for setmode() */
53 #endif
54
55 static char const rcsid[] = "$Id: mypopen.c,v 1.14 2006/04/21 10:40:29 broeker Exp $";
56
57 static pid_t popen_pid[20];
58 static RETSIGTYPE (*tstat)(int);
59
60 int
61 myopen(char *path, int flag, int mode)
62 {
63     /* opens a file descriptor and then sets close-on-exec for the file */
64     int fd;
65
66     /* 20020103: if file is not explicitly in Binary mode, make
67      * sure we override silly Cygwin behaviour of automatic binary
68      * mode for files in "binary mounted" paths */
69 #if O_BINARY != O_TEXT
70     if (! (flag | O_BINARY))
71         flag |= O_TEXT;
72 #endif
73     if(mode)
74         fd = open(path, flag, mode);
75     else
76         fd = open(path, flag);
77
78 #ifdef __DJGPP__                /* FIXME: test feature, not platform */
79     /* HBB 20010312: DOS GCC doesn't have FD_CLOEXEC (yet), so it 
80      * always fails this call. Have to skip that step */
81     if(fd != -1)
82         return(fd);
83 #endif
84     if(fd != -1 && (fcntl(fd, F_SETFD, CLOSE_ON_EXEC) != -1))
85         return(fd);
86
87     else
88         {
89             /* Ensure that if the fcntl fails and fd is valid, then
90                the file is closed properly. In general this should
91                not happen. */
92             if (fd != -1)
93                 {
94                     close (fd);
95                 }
96
97             return(-1);
98         }
99 }
100
101 FILE *
102 myfopen(char *path, char *mode)
103 {
104     /* opens a file pointer and then sets close-on-exec for the file */
105     FILE *fp;
106
107     fp = fopen(path, mode);
108
109 #ifdef SETMODE
110     if (fp && ! strchr(mode, 'b')) {
111         SETMODE(fileno(fp), O_TEXT);
112     }
113 #endif /* SETMODE */
114         
115 #ifdef __DJGPP__ /* FIXME: test feature, not platform */
116     /* HBB 20010312: DOS GCC doesn't have FD_CLOEXEC (yet), so it 
117      * always fails this call. Have to skip that step */
118     if(fp)
119 #else
120         if(fp && (fcntl(fileno(fp), F_SETFD, CLOSE_ON_EXEC) != -1))
121 #endif
122             return(fp);
123
124         else
125             return(NULL);
126 }
127
128 FILE *
129 mypopen(char *cmd, char *mode)
130 {
131 #ifdef __DJGPP__
132         /* HBB 20010312: Has its own implementation of popen(), which
133          * is better suited to the platform than cscope's */
134         return (popen)(cmd, mode);
135 #else
136         int     p[2];
137         pid_t *poptr;
138         int myside, yourside;
139         pid_t pid;
140
141         if(pipe(p) < 0)
142                 return(NULL);
143         myside = tst(p[WTR], p[RDR]);
144         yourside = tst(p[RDR], p[WTR]);
145         if((pid = fork()) == 0) {
146                 /* myside and yourside reverse roles in child */
147                 int     stdio;
148
149                 /* close all pipes from other popen's */
150                 for (poptr = popen_pid; poptr < popen_pid+20; poptr++) {
151                         if(*poptr)
152                                 (void) close(poptr - popen_pid);
153                 }
154                 stdio = tst(0, 1);
155                 close(myside);
156                 close(stdio);
157 #if V9
158                 dup2(yourside, stdio);
159 #else
160                 fcntl(yourside, F_DUPFD, stdio);
161 #endif
162                 close(yourside);
163                 execlp(shell, mybasename(shell), "-c", cmd, (void *)0);
164                 _exit(1);
165         } else if (pid > 0)
166                 tstat = signal(SIGTSTP, SIG_DFL);
167         if(pid == -1)
168                 return(NULL);
169         popen_pid[myside] = pid;
170         (void) close(yourside);
171         return(fdopen(myside, mode));
172 #endif /* DJGPP */
173 }
174
175 /* HBB 20010705: renamed from 'pclose', which would collide with
176  * system-supplied function of same name */
177 int
178 mypclose(FILE *ptr)
179 {
180         int f;
181         pid_t r;
182         int status;
183         sighandler_t hstat, istat, qstat;
184
185 #ifdef __DJGPP__ 
186         /* HBB 20010705: This system has its own pclose(), which we
187          * don't want to replace */
188         return (pclose)(ptr);
189 #else
190         f = fileno(ptr);
191         (void) fclose(ptr);
192         istat = signal(SIGINT, SIG_IGN);
193         qstat = signal(SIGQUIT, SIG_IGN);
194         hstat = signal(SIGHUP, SIG_IGN);
195         while((r = wait(&status)) != popen_pid[f] && r != -1)
196                 ;
197         if(r == -1)
198                 status = -1;
199         (void) signal(SIGINT, istat);
200         (void) signal(SIGQUIT, qstat);
201         (void) signal(SIGHUP, hstat);
202         (void) signal(SIGTSTP, tstat);
203         /* mark this pipe closed */
204         popen_pid[f] = 0;
205         return(status);
206 #endif /* DJGPP */
207 }