|
1
|
/* |
|
2
|
** Copyright (c) 2010 D. Richard Hipp |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the Simplified BSD License (also |
|
6
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
7
|
|
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but without any warranty; without even the implied warranty of |
|
10
|
** merchantability or fitness for a particular purpose. |
|
11
|
** |
|
12
|
** Author contact information: |
|
13
|
** [email protected] |
|
14
|
** http://www.hwaci.com/drh/ |
|
15
|
** |
|
16
|
******************************************************************************* |
|
17
|
** |
|
18
|
** This file contains an implementation of a bi-directional popen(). |
|
19
|
*/ |
|
20
|
#include "config.h" |
|
21
|
#include "popen.h" |
|
22
|
|
|
23
|
#ifdef _WIN32 |
|
24
|
#include <windows.h> |
|
25
|
#include <fcntl.h> |
|
26
|
/* |
|
27
|
** Print a fatal error and quit. |
|
28
|
*/ |
|
29
|
static void win32_fatal_error(const char *zMsg){ |
|
30
|
fossil_fatal("%s", zMsg); |
|
31
|
} |
|
32
|
#else |
|
33
|
#include <signal.h> |
|
34
|
#include <sys/wait.h> |
|
35
|
#endif |
|
36
|
|
|
37
|
/* |
|
38
|
** The following macros are used to cast pointers to integers and |
|
39
|
** integers to pointers. The way you do this varies from one compiler |
|
40
|
** to the next, so we have developed the following set of #if statements |
|
41
|
** to generate appropriate macros for a wide range of compilers. |
|
42
|
** |
|
43
|
** The correct "ANSI" way to do this is to use the intptr_t type. |
|
44
|
** Unfortunately, that typedef is not available on all compilers, or |
|
45
|
** if it is available, it requires an #include of specific headers |
|
46
|
** that vary from one machine to the next. |
|
47
|
** |
|
48
|
** This code is copied out of SQLite. |
|
49
|
*/ |
|
50
|
#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ |
|
51
|
# define INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) |
|
52
|
# define PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) |
|
53
|
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */ |
|
54
|
# define INT_TO_PTR(X) ((void*)&((char*)0)[X]) |
|
55
|
# define PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) |
|
56
|
#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ |
|
57
|
# define INT_TO_PTR(X) ((void*)(intptr_t)(X)) |
|
58
|
# define PTR_TO_INT(X) ((int)(intptr_t)(X)) |
|
59
|
#else /* Generates a warning - but it always works */ |
|
60
|
# define INT_TO_PTR(X) ((void*)(X)) |
|
61
|
# define PTR_TO_INT(X) ((int)(X)) |
|
62
|
#endif |
|
63
|
|
|
64
|
|
|
65
|
#ifdef _WIN32 |
|
66
|
/* |
|
67
|
** On windows, create a child process and specify the stdin, stdout, |
|
68
|
** and stderr channels for that process to use. |
|
69
|
** |
|
70
|
** Return the number of errors. |
|
71
|
*/ |
|
72
|
static int win32_create_child_process( |
|
73
|
wchar_t *zCmd, /* The command that the child process will run */ |
|
74
|
HANDLE hIn, /* Standard input */ |
|
75
|
HANDLE hOut, /* Standard output */ |
|
76
|
HANDLE hErr, /* Standard error */ |
|
77
|
DWORD *pChildPid /* OUT: Child process handle */ |
|
78
|
){ |
|
79
|
STARTUPINFOW si; |
|
80
|
PROCESS_INFORMATION pi; |
|
81
|
BOOL rc; |
|
82
|
|
|
83
|
memset(&si, 0, sizeof(si)); |
|
84
|
si.cb = sizeof(si); |
|
85
|
si.dwFlags = STARTF_USESTDHANDLES; |
|
86
|
SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, TRUE); |
|
87
|
si.hStdInput = hIn; |
|
88
|
SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, TRUE); |
|
89
|
si.hStdOutput = hOut; |
|
90
|
SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, TRUE); |
|
91
|
si.hStdError = hErr; |
|
92
|
rc = CreateProcessW( |
|
93
|
NULL, /* Application Name */ |
|
94
|
zCmd, /* Command-line */ |
|
95
|
NULL, /* Process attributes */ |
|
96
|
NULL, /* Thread attributes */ |
|
97
|
TRUE, /* Inherit Handles */ |
|
98
|
0, /* Create flags */ |
|
99
|
NULL, /* Environment */ |
|
100
|
NULL, /* Current directory */ |
|
101
|
&si, /* Startup Info */ |
|
102
|
&pi /* Process Info */ |
|
103
|
); |
|
104
|
if( rc ){ |
|
105
|
CloseHandle( pi.hProcess ); |
|
106
|
CloseHandle( pi.hThread ); |
|
107
|
*pChildPid = pi.dwProcessId; |
|
108
|
}else{ |
|
109
|
win32_fatal_error("cannot create child process"); |
|
110
|
} |
|
111
|
return rc!=0; |
|
112
|
} |
|
113
|
#endif |
|
114
|
|
|
115
|
/* |
|
116
|
** Create a child process running shell command "zCmd". *ppOut is |
|
117
|
** a FILE that becomes the standard input of the child process. |
|
118
|
** (The caller writes to *ppOut in order to send text to the child.) |
|
119
|
** *ppIn is stdout from the child process. (The caller |
|
120
|
** reads from *ppIn in order to receive input from the child.) |
|
121
|
** Note that *ppIn is an unbuffered file descriptor, not a FILE. |
|
122
|
** The process ID of the child is written into *pChildPid. |
|
123
|
** |
|
124
|
** Return the number of errors. |
|
125
|
*/ |
|
126
|
int popen2( |
|
127
|
const char *zCmd, /* Command to run in the child process */ |
|
128
|
int *pfdIn, /* Read from child using this file descriptor */ |
|
129
|
FILE **ppOut, /* Write to child using this file descriptor */ |
|
130
|
int *pChildPid, /* PID of the child process */ |
|
131
|
int bDirect /* 0: run zCmd as a shell cmd. 1: run directly */ |
|
132
|
){ |
|
133
|
#ifdef _WIN32 |
|
134
|
HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr; |
|
135
|
SECURITY_ATTRIBUTES saAttr; |
|
136
|
DWORD childPid = 0; |
|
137
|
int fd; |
|
138
|
|
|
139
|
saAttr.nLength = sizeof(saAttr); |
|
140
|
saAttr.bInheritHandle = TRUE; |
|
141
|
saAttr.lpSecurityDescriptor = NULL; |
|
142
|
hStderr = GetStdHandle(STD_ERROR_HANDLE); |
|
143
|
if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){ |
|
144
|
win32_fatal_error("cannot create pipe for stdout"); |
|
145
|
} |
|
146
|
SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE); |
|
147
|
|
|
148
|
if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){ |
|
149
|
win32_fatal_error("cannot create pipe for stdin"); |
|
150
|
} |
|
151
|
SetHandleInformation( hStdinWr, HANDLE_FL |