Fossil SCM

fossil-scm / src / popen.c
Blame History Raw 151 lines
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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button