]>
Commit | Line | Data |
---|---|---|
bc78a6d5 RC |
1 | /* |
2 | * Copyright (c) 2001, Jan Nieuwenhuizen. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by DJ Delorie <dj@cygnus.com> | |
13 | * Jan Nieuwenhuizen <janneke@gnu.org> | |
14 | * | |
15 | */ | |
16 | ||
17 | /* The purpose of this file is to provide functions for the invocation | |
18 | of install scripts. */ | |
19 | ||
20 | #if 0 | |
21 | static const char *cvsid = | |
22 | "\n%%% $Id$\n"; | |
23 | #endif | |
24 | ||
25 | #include "win32.h" | |
26 | #include <stdlib.h> | |
27 | #include <unistd.h> | |
28 | #include <stdio.h> | |
1069407c | 29 | #include "LogSingleton.h" |
3c054baf | 30 | #include "filemanip.h" |
bc78a6d5 RC |
31 | #include "mount.h" |
32 | #include "io_stream.h" | |
ad646f43 | 33 | #include "script.h" |
1069407c | 34 | #include "mkdir.h" |
bc78a6d5 | 35 | |
3c054baf | 36 | static String sh = String(); |
bc78a6d5 RC |
37 | static const char *cmd = 0; |
38 | static OSVERSIONINFO verinfo; | |
39 | ||
40 | static const char *shells[] = { | |
534c25cc BD |
41 | // Bash is guaranteed to exist, /bin/sh is not. Besides, |
42 | // upgrading /bin/sh requires that /bin/sh not be used. | |
bc78a6d5 RC |
43 | "/bin/bash.exe", |
44 | "/usr/bin/bash.exe", | |
45 | 0 | |
46 | }; | |
47 | ||
48 | void | |
49 | init_run_script () | |
50 | { | |
51 | for (int i = 0; shells[i]; i++) | |
52 | { | |
1ac649ed | 53 | sh = backslash (cygpath (shells[i])); |
d2a3615c | 54 | if (_access (sh.c_str(), 0) == 0) |
bc78a6d5 | 55 | break; |
3c054baf | 56 | sh = String(); |
bc78a6d5 RC |
57 | } |
58 | ||
4875ac88 | 59 | char old_path[MAX_PATH]; |
bc78a6d5 | 60 | GetEnvironmentVariable ("PATH", old_path, sizeof (old_path)); |
1ac649ed RC |
61 | SetEnvironmentVariable ("PATH", backslash (cygpath ("/bin") + ";" + |
62 | cygpath ("/usr/bin") + ";" + | |
d2a3615c MB |
63 | old_path).c_str()); |
64 | SetEnvironmentVariable ("CYGWINROOT", get_root_dir ().c_str()); | |
bc78a6d5 RC |
65 | |
66 | verinfo.dwOSVersionInfoSize = sizeof (verinfo); | |
67 | GetVersionEx (&verinfo); | |
68 | ||
69 | switch (verinfo.dwPlatformId) | |
70 | { | |
71 | case VER_PLATFORM_WIN32_NT: | |
72 | cmd = "cmd.exe"; | |
73 | break; | |
74 | case VER_PLATFORM_WIN32_WINDOWS: | |
75 | cmd = "command.com"; | |
76 | break; | |
77 | default: | |
78 | cmd = "command.com"; | |
79 | break; | |
80 | } | |
81 | } | |
82 | ||
1069407c MB |
83 | class OutputLog |
84 | { | |
85 | public: | |
86 | OutputLog (String const &filename); | |
87 | ~OutputLog (); | |
88 | HANDLE handle () { return _handle; } | |
89 | BOOL isValid () { return _handle != INVALID_HANDLE_VALUE; } | |
90 | BOOL isEmpty () { return GetFileSize (_handle, NULL) == 0; } | |
91 | friend std::ostream &operator<< (std::ostream &, OutputLog &); | |
92 | private: | |
93 | enum { BUFLEN = 1000 }; | |
94 | HANDLE _handle; | |
95 | String _filename; | |
96 | void out_to(std::ostream &); | |
97 | }; | |
98 | ||
99 | OutputLog::OutputLog (String const &filename) | |
100 | : _handle(INVALID_HANDLE_VALUE), _filename(filename) | |
101 | { | |
102 | if (!_filename.size()) | |
103 | return; | |
104 | ||
105 | SECURITY_ATTRIBUTES sa; | |
106 | memset (&sa, 0, sizeof (sa)); | |
107 | sa.nLength = sizeof (sa); | |
108 | sa.bInheritHandle = TRUE; | |
109 | sa.lpSecurityDescriptor = NULL; | |
110 | ||
d2a3615c | 111 | if (mkdir_p (0, backslash (cygpath (_filename)).c_str())) |
1069407c MB |
112 | return; |
113 | ||
d2a3615c | 114 | _handle = CreateFile (backslash (cygpath (_filename)).c_str(), |
1069407c MB |
115 | GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, |
116 | &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
117 | ||
118 | if (_handle == INVALID_HANDLE_VALUE) | |
119 | { | |
120 | log(LOG_PLAIN) << "error: Unable to redirect output to '" << _filename | |
121 | << "'; using console" << endLog; | |
122 | } | |
123 | } | |
124 | ||
125 | OutputLog::~OutputLog () | |
126 | { | |
127 | if (_handle != INVALID_HANDLE_VALUE) | |
128 | CloseHandle (_handle); | |
129 | if (_filename.size() && | |
d2a3615c | 130 | !DeleteFile(backslash (cygpath (_filename)).c_str())) |
1069407c MB |
131 | { |
132 | log(LOG_PLAIN) << "error: Unable to remove temporary file '" << _filename | |
133 | << "'" << endLog; | |
134 | } | |
135 | } | |
136 | ||
137 | std::ostream & | |
138 | operator<< (std::ostream &out, OutputLog &log) | |
139 | { | |
140 | log.out_to(out); | |
141 | return out; | |
142 | } | |
143 | ||
144 | void | |
145 | OutputLog::out_to(std::ostream &out) | |
146 | { | |
147 | char buf[BUFLEN]; | |
148 | DWORD num; | |
149 | FlushFileBuffers (_handle); | |
150 | SetFilePointer(_handle, 0, NULL, FILE_BEGIN); | |
151 | ||
152 | while (ReadFile(_handle, buf, BUFLEN-1, &num, NULL) && num != 0) | |
153 | { | |
154 | buf[num] = '\0'; | |
155 | out << buf; | |
156 | } | |
157 | ||
158 | SetFilePointer(_handle, 0, NULL, FILE_END); | |
159 | } | |
160 | ||
534c25cc | 161 | static int |
1069407c | 162 | run (const char *sh, const char *args, const char *file, OutputLog &file_out) |
bc78a6d5 | 163 | { |
4875ac88 | 164 | char cmdline[MAX_PATH]; |
bc78a6d5 RC |
165 | STARTUPINFO si; |
166 | PROCESS_INFORMATION pi; | |
1069407c | 167 | DWORD flags = CREATE_NEW_CONSOLE; |
534c25cc | 168 | DWORD exitCode = 0; |
1069407c | 169 | BOOL inheritHandles = FALSE; |
534c25cc | 170 | BOOL exitCodeValid = FALSE; |
bc78a6d5 RC |
171 | |
172 | sprintf (cmdline, "%s %s %s", sh, args, file); | |
173 | memset (&pi, 0, sizeof (pi)); | |
174 | memset (&si, 0, sizeof (si)); | |
175 | si.cb = sizeof (si); | |
176 | si.lpTitle = (char *) "Cygwin Setup Post-Install Script"; | |
177 | si.dwFlags = STARTF_USEPOSITION; | |
178 | ||
1069407c MB |
179 | if (file_out.isValid ()) |
180 | { | |
181 | inheritHandles = TRUE; | |
182 | si.dwFlags |= STARTF_USESTDHANDLES; | |
5524909e | 183 | si.hStdInput = INVALID_HANDLE_VALUE; |
1069407c MB |
184 | si.hStdOutput = file_out.handle (); |
185 | si.hStdError = file_out.handle (); | |
186 | si.dwFlags |= STARTF_USESHOWWINDOW; | |
1069407c | 187 | si.wShowWindow = SW_HIDE; |
39ba3555 | 188 | flags = CREATE_NO_WINDOW; // Note: this is ignored on Win9x |
1069407c MB |
189 | } |
190 | ||
191 | BOOL createSucceeded = CreateProcess (0, cmdline, 0, 0, inheritHandles, | |
d2a3615c | 192 | flags, 0, get_root_dir ().c_str(), |
1069407c | 193 | &si, &pi); |
bc78a6d5 | 194 | |
92f9402a | 195 | if (createSucceeded) |
534c25cc BD |
196 | { |
197 | WaitForSingleObject (pi.hProcess, INFINITE); | |
198 | exitCodeValid = GetExitCodeProcess(pi.hProcess, &exitCode); | |
199 | } | |
92f9402a RC |
200 | CloseHandle(pi.hProcess); |
201 | CloseHandle(pi.hThread); | |
534c25cc BD |
202 | if (exitCodeValid) |
203 | return exitCode; | |
204 | return -GetLastError(); | |
bc78a6d5 RC |
205 | } |
206 | ||
1e3b2ad4 RC |
207 | char const * |
208 | Script::extension() const | |
209 | { | |
d2a3615c | 210 | return strrchr (scriptName.c_str(), '.'); |
1e3b2ad4 RC |
211 | } |
212 | ||
534c25cc | 213 | int |
34ea5b6d | 214 | Script::run() const |
a0e56f67 | 215 | { |
1e3b2ad4 | 216 | if (!extension()) |
534c25cc | 217 | return -ERROR_INVALID_DATA; |
bc78a6d5 | 218 | |
34ea5b6d | 219 | BOOL to_log (TRUE); |
1069407c | 220 | String log_name = ""; |
534c25cc | 221 | int retval = 0; |
1069407c MB |
222 | if (to_log) |
223 | { | |
224 | char tmp_pat[] = "/var/log/setup.log.postinstallXXXXXXX"; | |
225 | log_name = String (mktemp(tmp_pat)); | |
226 | } | |
227 | OutputLog file_out(log_name); | |
228 | ||
1e3b2ad4 | 229 | if (sh.size() && strcmp (extension(), ".sh") == 0) |
bc78a6d5 | 230 | { |
9f27ab95 | 231 | log(LOG_PLAIN) << "running: " << sh << " -c " << scriptName << endLog; |
534c25cc | 232 | retval = ::run (sh.c_str(), "-c", scriptName.c_str(), file_out); |
bc78a6d5 | 233 | } |
1e3b2ad4 | 234 | else if (cmd && strcmp (extension(), ".bat") == 0) |
bc78a6d5 | 235 | { |
9f27ab95 RC |
236 | String windowsName = backslash (cygpath (scriptName)); |
237 | log(LOG_PLAIN) << "running: " << cmd << " /c " << windowsName << endLog; | |
534c25cc | 238 | retval = ::run (cmd, "/c", windowsName.c_str(), file_out); |
bc78a6d5 RC |
239 | } |
240 | else | |
534c25cc | 241 | return -ERROR_INVALID_DATA; |
bc78a6d5 | 242 | |
1069407c MB |
243 | if (to_log && !file_out.isEmpty ()) |
244 | log(LOG_BABBLE) << file_out << endLog; | |
245 | ||
b2b35a6e | 246 | if (retval) |
534c25cc BD |
247 | log(LOG_PLAIN) << "abnormal exit: exit code=" << retval << endLog;; |
248 | ||
bc78a6d5 | 249 | /* if file exists then delete it otherwise just ignore no file error */ |
783ed9c5 | 250 | io_stream::remove (String ("cygfile://") + scriptName + ".done"); |
bc78a6d5 | 251 | |
783ed9c5 RC |
252 | io_stream::move (String ("cygfile://") + scriptName, |
253 | String ("cygfile://") + scriptName + ".done"); | |
534c25cc BD |
254 | |
255 | return retval; | |
bc78a6d5 RC |
256 | } |
257 | ||
534c25cc BD |
258 | int |
259 | try_run_script (String const &dir, String const &fname, String const &ext) | |
bc78a6d5 | 260 | { |
534c25cc BD |
261 | if (io_stream::exists (String ("cygfile://") + dir + fname + ext)) |
262 | return Script (dir + fname + ext).run (); | |
263 | return NO_ERROR; | |
bc78a6d5 RC |
264 | } |
265 | ||
39ba3555 MB |
266 | char const Script::ETCPostinstall[] = "/etc/postinstall/"; |
267 | ||
ad646f43 RC |
268 | bool |
269 | Script::isAScript (String const &file) | |
270 | { | |
271 | /* file may be /etc/postinstall or etc/postinstall */ | |
afa76033 MB |
272 | if (casecompare(file, ETCPostinstall, sizeof(ETCPostinstall)-1) && |
273 | casecompare(file, ETCPostinstall+1, sizeof(ETCPostinstall)-2)) | |
ad646f43 | 274 | return false; |
d2a3615c | 275 | if (file.c_str()[file.size() - 1] == '/') |
ad646f43 RC |
276 | return false; |
277 | return true; | |
278 | } | |
279 | ||
280 | Script::Script (String const &fileName) : scriptName (fileName) | |
281 | { | |
282 | ||
283 | } | |
284 | ||
285 | String | |
39ba3555 | 286 | Script::baseName() const |
ad646f43 RC |
287 | { |
288 | String result = scriptName; | |
289 | while (result.find ('/')) | |
290 | result = result.substr(result.find ('/')); | |
291 | return result; | |
292 | } | |
39ba3555 MB |
293 | |
294 | String | |
295 | Script::fullName() const | |
296 | { | |
297 | return scriptName; | |
298 | } |