]> cygwin.com Git - cygwin-apps/setup.git/blame - script.cc
2006-03-30 Max Bowsher <maxb1@ukf.net>
[cygwin-apps/setup.git] / script.cc
CommitLineData
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
21static 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 36static String sh = String();
bc78a6d5
RC
37static const char *cmd = 0;
38static OSVERSIONINFO verinfo;
39
40static 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
48void
49init_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
83class OutputLog
84{
85public:
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 &);
92private:
93 enum { BUFLEN = 1000 };
94 HANDLE _handle;
95 String _filename;
96 void out_to(std::ostream &);
97};
98
99OutputLog::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
125OutputLog::~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
137std::ostream &
138operator<< (std::ostream &out, OutputLog &log)
139{
140 log.out_to(out);
141 return out;
142}
143
144void
145OutputLog::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 161static int
1069407c 162run (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
207char const *
208Script::extension() const
209{
d2a3615c 210 return strrchr (scriptName.c_str(), '.');
1e3b2ad4
RC
211}
212
534c25cc 213int
34ea5b6d 214Script::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
258int
259try_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
266char const Script::ETCPostinstall[] = "/etc/postinstall/";
267
ad646f43
RC
268bool
269Script::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
280Script::Script (String const &fileName) : scriptName (fileName)
281{
282
283}
284
285String
39ba3555 286Script::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
294String
295Script::fullName() const
296{
297 return scriptName;
298}
This page took 0.082275 seconds and 5 git commands to generate.