2 * os_win32/popen_win32.cpp
4 * Home page of code is: https://www.smartmontools.org
6 * Copyright (C) 2018 Christian Franke
8 * SPDX-License-Identifier: GPL-2.0-or-later
13 const char * popen_win32_cpp_cvsid
= "$Id: popen_win32.cpp 4818 2018-10-17 05:32:17Z chrfranke $"
18 #include <io.h> // _open_osfhandle()
19 #include <signal.h> // SIGSEGV
23 #define WIN32_LEAN_AND_MEAN
26 static FILE * s_popen_file
;
27 static HANDLE s_popen_process
;
30 FILE * popen(const char * command
, const char * mode
)
32 // Fail if previous run is still in progress
38 // mode "w" is not implemented
39 if (!(mode
[0] == 'r' && (!mode
[1] || !mode
[2]))) {
44 // Set flags for text or binary mode
45 // Note: _open_osfhandle() ignores _fmode and defaults to O_BINARY
46 int oflags
; const char * fomode
;
50 oflags
= O_RDONLY
|O_TEXT
;
54 oflags
= O_RDONLY
|O_BINARY
;
62 // Create stdout pipe with inheritable write end
63 HANDLE pipe_out_r
, pipe_out_w
;
64 if (!CreatePipe(&pipe_out_r
, &pipe_out_w
, (SECURITY_ATTRIBUTES
*)0, 1024)) {
68 if (!SetHandleInformation(pipe_out_w
, HANDLE_FLAG_INHERIT
, HANDLE_FLAG_INHERIT
)) {
69 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
74 // Connect pipe read end to new FD
75 int fd
= _open_osfhandle((intptr_t)pipe_out_r
, oflags
);
77 CloseHandle(pipe_out_r
); CloseHandle(pipe_out_w
);
81 // Connect FD to new FILE
82 FILE * f
= fdopen(fd
, fomode
);
85 close(fd
); // CloseHandle(pipe_out_r)
86 CloseHandle(pipe_out_w
);
91 // Build command line "cmd /c COMMAND"
92 int cmdlen
= strlen(command
);
93 char * shellcmd
= (char *)malloc(7 + cmdlen
+ 1);
95 fclose(f
); // CloseHandle(pipe_out_r)
96 CloseHandle(pipe_out_w
);
100 memcpy(shellcmd
, "cmd /c ", 7);
101 memcpy(shellcmd
+ 7, command
, cmdlen
+ 1);
103 // Redirect stdin stderr to null device
104 // Don't inherit parent's stdin, script may hang if parent has no console.
105 SECURITY_ATTRIBUTES sa_inherit
= { sizeof(sa_inherit
), (SECURITY_DESCRIPTOR
*)0, TRUE
};
106 HANDLE null_in
= CreateFile("nul", GENERIC_READ
, 0, &sa_inherit
, OPEN_EXISTING
, 0, (HANDLE
)0);
107 HANDLE null_err
= CreateFile("nul", GENERIC_WRITE
, 0, &sa_inherit
, OPEN_EXISTING
, 0, (HANDLE
)0);
110 STARTUPINFO si
; memset(&si
, 0, sizeof(si
)); si
.cb
= sizeof(si
);
111 si
.hStdInput
= null_in
;
112 si
.hStdOutput
= pipe_out_w
;
113 si
.hStdError
= null_err
;
114 si
.dwFlags
= STARTF_USESTDHANDLES
;
117 PROCESS_INFORMATION pi
;
118 BOOL ok
= CreateProcessA(
119 getenv("COMSPEC"), // "C:\WINDOWS\system32\cmd.exe" or nullptr
120 shellcmd
, // "cmd /c COMMAND" ("cmd" searched in PATH if COMSPEC not set)
121 (SECURITY_ATTRIBUTES
*)0, (SECURITY_ATTRIBUTES
*)0,
123 CREATE_NO_WINDOW
, // DETACHED_PROCESS would open new console(s)
124 (void *)0, (char *)0, &si
, &pi
128 // Close inherited handles
129 CloseHandle(null_err
);
130 CloseHandle(null_in
);
131 CloseHandle(pipe_out_w
);
134 fclose(f
); // CloseHandle(pipe_out_r)
139 // Store process and FILE for pclose()
140 CloseHandle(pi
.hThread
);
141 s_popen_process
= pi
.hProcess
;
150 if (f
!= s_popen_file
) {
158 // Wait for process exitcode
160 bool ok
= ( WaitForSingleObject(s_popen_process
, INFINITE
) == WAIT_OBJECT_0
161 && GetExitCodeProcess(s_popen_process
, &exitcode
));
163 CloseHandle(s_popen_process
);
171 // Modify exitcode for wait(3) macros
173 return ((exitcode
<< 9) >> 1) | SIGSEGV
;
175 return exitcode
<< 8;