]> cygwin.com Git - cygwin-apps/setup.git/blame - script.cc
* Makefile.am (AM_CXXFLAGS): Add source file specific CXXFLAGS.
[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"
c3d07c13
AK
35#include "state.h"
36#include "resource.h"
5a85457b
CF
37#if HAVE_ALLOCA_H
38#include <alloca.h>
39#else
40#ifndef alloca
41#define alloca __builtin_alloca
42#endif
43#endif
bc78a6d5 44
2bba98e8 45static std::string sh;
b56d411d 46static const char *cmd;
5a85457b
CF
47
48static void
49sanitize_PATH ()
50{
51 char dummy;
52 DWORD len = GetEnvironmentVariable ("PATH", &dummy, 0);
53 char *path = (char *) alloca (len + 1);
54 GetEnvironmentVariable ("PATH", path, len);
55 std::string newpath = backslash (cygpath ("/bin") + ";"
56 + cygpath ("/usr/sbin") + ";"
57 + cygpath ("/sbin"));
58 len = (UINT) GetWindowsDirectory (&dummy, 0);
59 char *system_root = (char *) alloca (len + 2);
60 GetWindowsDirectory (system_root, len--);
61 if (system_root[len - 1] != '\\')
62 {
63 system_root[len] = '\\';
64 system_root[++len] = '\0';
65 }
66 for (char *p = strtok (path, ";"); p; p = strtok (NULL, ";"))
67 {
68 size_t plen = strlen (p);
69 size_t cmplen = plen == (len - 1) ? plen : len;
70 if (strncasecmp (system_root, p, cmplen) == 0)
71 {
72 newpath += ";";
73 newpath += p;
74 }
75 }
76 SetEnvironmentVariable ("PATH", newpath.c_str());
77}
78
bc78a6d5
RC
79
80void
81init_run_script ()
82{
5a85457b
CF
83 static bool initialized;
84 if (initialized)
85 return;
86
87 initialized = true;
88
89 char *env = GetEnvironmentStrings ();
90 if (env)
bc78a6d5 91 {
5a85457b
CF
92 for (char *p = env; *p; p = strchr (p, '\0') + 1)
93 {
94 char *eq = strchr (p, '=');
95 *eq = '\0';
96 if (strcasecmp (p, "comspec") != 0
97 && strcasecmp (p, "path") != 0
98 && strncasecmp (p, "system", 7) != 0
99 && strncasecmp (p, "user", 4) != 0
100 && strcasecmp (p, "windir") != 0)
101 SetEnvironmentVariable (p, NULL);
102 p = eq + 1;
103 }
104 FreeEnvironmentStrings (env);
bc78a6d5 105 }
5a85457b 106
d2a3615c 107 SetEnvironmentVariable ("CYGWINROOT", get_root_dir ().c_str());
c3d07c13
AK
108 SetEnvironmentVariable ("CYGWINFORALL",
109 (root_scope == IDC_ROOT_SYSTEM) ? "-A" : NULL);
5a85457b
CF
110 sanitize_PATH ();
111 SetEnvironmentVariable ("SHELL", "/bin/bash");
112 SetEnvironmentVariable ("TEMP", backslash (cygpath ("/tmp")).c_str ());
113 SetEnvironmentVariable ("TERM", "dumb");
114 SetEnvironmentVariable ("TMP", "/tmp");
bc78a6d5 115
46cf12cd 116 sh = backslash (cygpath ("/bin/bash.exe"));
1e029da2 117 cmd = "cmd.exe";
bc78a6d5
RC
118}
119
1069407c
MB
120class OutputLog
121{
122public:
2bba98e8 123 OutputLog (const std::string& filename);
1069407c
MB
124 ~OutputLog ();
125 HANDLE handle () { return _handle; }
126 BOOL isValid () { return _handle != INVALID_HANDLE_VALUE; }
127 BOOL isEmpty () { return GetFileSize (_handle, NULL) == 0; }
128 friend std::ostream &operator<< (std::ostream &, OutputLog &);
129private:
130 enum { BUFLEN = 1000 };
131 HANDLE _handle;
2bba98e8 132 std::string _filename;
1069407c
MB
133 void out_to(std::ostream &);
134};
135
2bba98e8 136OutputLog::OutputLog (const std::string& filename)
1069407c
MB
137 : _handle(INVALID_HANDLE_VALUE), _filename(filename)
138{
139 if (!_filename.size())
140 return;
141
142 SECURITY_ATTRIBUTES sa;
143 memset (&sa, 0, sizeof (sa));
144 sa.nLength = sizeof (sa);
145 sa.bInheritHandle = TRUE;
146 sa.lpSecurityDescriptor = NULL;
147
b41c2908 148 if (mkdir_p (0, backslash (cygpath (_filename)).c_str(), 0755))
1069407c
MB
149 return;
150
d2a3615c 151 _handle = CreateFile (backslash (cygpath (_filename)).c_str(),
1069407c 152 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
b41c2908
CV
153 &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
154 NULL);
1069407c
MB
155
156 if (_handle == INVALID_HANDLE_VALUE)
157 {
158 log(LOG_PLAIN) << "error: Unable to redirect output to '" << _filename
159 << "'; using console" << endLog;
160 }
161}
162
163OutputLog::~OutputLog ()
164{
165 if (_handle != INVALID_HANDLE_VALUE)
166 CloseHandle (_handle);
167 if (_filename.size() &&
d2a3615c 168 !DeleteFile(backslash (cygpath (_filename)).c_str()))
1069407c
MB
169 {
170 log(LOG_PLAIN) << "error: Unable to remove temporary file '" << _filename
171 << "'" << endLog;
172 }
173}
174
175std::ostream &
176operator<< (std::ostream &out, OutputLog &log)
177{
178 log.out_to(out);
179 return out;
180}
181
182void
183OutputLog::out_to(std::ostream &out)
184{
185 char buf[BUFLEN];
186 DWORD num;
187 FlushFileBuffers (_handle);
188 SetFilePointer(_handle, 0, NULL, FILE_BEGIN);
189
190 while (ReadFile(_handle, buf, BUFLEN-1, &num, NULL) && num != 0)
191 {
192 buf[num] = '\0';
193 out << buf;
194 }
195
196 SetFilePointer(_handle, 0, NULL, FILE_END);
197}
198
f2952a6c
JT
199int
200run (const char *cmdline)
bc78a6d5 201{
f2952a6c 202
bc78a6d5
RC
203 STARTUPINFO si;
204 PROCESS_INFORMATION pi;
1069407c 205 DWORD flags = CREATE_NEW_CONSOLE;
534c25cc 206 DWORD exitCode = 0;
1069407c 207 BOOL inheritHandles = FALSE;
534c25cc 208 BOOL exitCodeValid = FALSE;
bc78a6d5 209
f2952a6c
JT
210 log(LOG_PLAIN) << "running: " << cmdline << endLog;
211
212 char tmp_pat[] = "/var/log/setup.log.runXXXXXXX";
213 OutputLog file_out = std::string (mktemp (tmp_pat));
214
bc78a6d5
RC
215 memset (&pi, 0, sizeof (pi));
216 memset (&si, 0, sizeof (si));
217 si.cb = sizeof (si);
218 si.lpTitle = (char *) "Cygwin Setup Post-Install Script";
219 si.dwFlags = STARTF_USEPOSITION;
220
1069407c
MB
221 if (file_out.isValid ())
222 {
223 inheritHandles = TRUE;
224 si.dwFlags |= STARTF_USESTDHANDLES;
5524909e 225 si.hStdInput = INVALID_HANDLE_VALUE;
1069407c
MB
226 si.hStdOutput = file_out.handle ();
227 si.hStdError = file_out.handle ();
228 si.dwFlags |= STARTF_USESHOWWINDOW;
1069407c 229 si.wShowWindow = SW_HIDE;
39ba3555 230 flags = CREATE_NO_WINDOW; // Note: this is ignored on Win9x
1069407c
MB
231 }
232
f2952a6c 233 BOOL createSucceeded = CreateProcess (0, (char *)cmdline, 0, 0, inheritHandles,
d2a3615c 234 flags, 0, get_root_dir ().c_str(),
1069407c 235 &si, &pi);
bc78a6d5 236
92f9402a 237 if (createSucceeded)
534c25cc
BD
238 {
239 WaitForSingleObject (pi.hProcess, INFINITE);
240 exitCodeValid = GetExitCodeProcess(pi.hProcess, &exitCode);
241 }
92f9402a
RC
242 CloseHandle(pi.hProcess);
243 CloseHandle(pi.hThread);
f2952a6c
JT
244
245 if (!file_out.isEmpty ())
246 log(LOG_BABBLE) << file_out << endLog;
247
534c25cc
BD
248 if (exitCodeValid)
249 return exitCode;
250 return -GetLastError();
bc78a6d5
RC
251}
252
1e3b2ad4
RC
253char const *
254Script::extension() const
255{
d2a3615c 256 return strrchr (scriptName.c_str(), '.');
1e3b2ad4
RC
257}
258
534c25cc 259int
34ea5b6d 260Script::run() const
a0e56f67 261{
1e3b2ad4 262 if (!extension())
534c25cc 263 return -ERROR_INVALID_DATA;
bc78a6d5 264
a875b471
BD
265 /* Bail here if the script file does not exist. This can happen for
266 example in the case of tetex-* where two or more packages contain a
267 postinstall script by the same name. When we are called the second
268 time the file has already been renamed to .done, and if we don't
269 return here we end up erroniously deleting this .done file. */
270 std::string windowsName = backslash (cygpath (scriptName));
271 if (_access (windowsName.c_str(), 0) == -1)
1069407c 272 {
a875b471
BD
273 log(LOG_PLAIN) << "can't run " << scriptName << ": No such file"
274 << endLog;
275 return -ERROR_INVALID_DATA;
1069407c 276 }
1069407c 277
a875b471 278 int retval;
f2952a6c
JT
279 char cmdline[MAX_PATH];
280
a875b471 281 if (sh.size() && stricmp (extension(), ".sh") == 0)
bc78a6d5 282 {
f2952a6c
JT
283 sprintf (cmdline, "%s %s \"%s\"", sh.c_str(), "--norc --noprofile", scriptName.c_str());
284 retval = ::run (cmdline);
bc78a6d5 285 }
a875b471 286 else if (cmd && stricmp (extension(), ".bat") == 0)
bc78a6d5 287 {
f2952a6c
JT
288 sprintf (cmdline, "%s %s \"%s\"", cmd, "/c", windowsName.c_str());
289 retval = ::run (cmdline);
bc78a6d5
RC
290 }
291 else
534c25cc 292 return -ERROR_INVALID_DATA;
bc78a6d5 293
b2b35a6e 294 if (retval)
a875b471 295 log(LOG_PLAIN) << "abnormal exit: exit code=" << retval << endLog;
534c25cc 296
0707786e 297 /* if .done file exists then delete it otherwise just ignore no file error */
2bba98e8 298 io_stream::remove ("cygfile://" + scriptName + ".done");
bc78a6d5 299
0707786e
JT
300 /* don't rename the script as .done if it didn't run successfully */
301 if (!retval)
302 io_stream::move ("cygfile://" + scriptName,
303 "cygfile://" + scriptName + ".done");
534c25cc
BD
304
305 return retval;
bc78a6d5
RC
306}
307
534c25cc 308int
2bba98e8
MB
309try_run_script (const std::string& dir,
310 const std::string& fname,
311 const std::string& ext)
bc78a6d5 312{
2bba98e8 313 if (io_stream::exists ("cygfile://" + dir + fname + ext))
534c25cc
BD
314 return Script (dir + fname + ext).run ();
315 return NO_ERROR;
bc78a6d5
RC
316}
317
39ba3555
MB
318char const Script::ETCPostinstall[] = "/etc/postinstall/";
319
ad646f43 320bool
2bba98e8 321Script::isAScript (const std::string& file)
ad646f43
RC
322{
323 /* file may be /etc/postinstall or etc/postinstall */
afa76033
MB
324 if (casecompare(file, ETCPostinstall, sizeof(ETCPostinstall)-1) &&
325 casecompare(file, ETCPostinstall+1, sizeof(ETCPostinstall)-2))
ad646f43 326 return false;
d2a3615c 327 if (file.c_str()[file.size() - 1] == '/')
ad646f43
RC
328 return false;
329 return true;
330}
331
2bba98e8 332Script::Script (const std::string& fileName) : scriptName (fileName)
ad646f43
RC
333{
334
335}
336
470f4928 337std::string
39ba3555 338Script::baseName() const
ad646f43 339{
470f4928
MB
340 std::string result = scriptName;
341 result = result.substr(result.rfind('/') + 1);
ad646f43
RC
342 return result;
343}
39ba3555 344
2bba98e8 345std::string
39ba3555
MB
346Script::fullName() const
347{
348 return scriptName;
349}
This page took 0.096606 seconds and 5 git commands to generate.