Mercurial > trustbridge
annotate ui/installwrapper.cpp @ 459:34cc448409ec
Fix error handling
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Wed, 23 Apr 2014 13:47:33 +0000 |
parents | a7163018de2f |
children | cef732072774 |
rev | line source |
---|---|
404 | 1 /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik |
2 * Software engineering by Intevation GmbH | |
3 * | |
4 * This file is Free Software under the GNU GPL (v>=2) | |
5 * and comes with ABSOLUTELY NO WARRANTY! | |
6 * See LICENSE.txt for details. | |
7 */ | |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
8 #include "installwrapper.h" |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
9 |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
10 #include <QFileInfo> |
364 | 11 #include <QProcess> |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
12 #include <QTemporaryFile> |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
13 #include <QApplication> |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
14 #include <QDir> |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
15 #include <QDebug> |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
16 |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
17 #include "logging.h" |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
18 |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
19 #define INSTALL_TIMEOUT 3600000 /* Wait up to an hour */ |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
20 |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
21 InstallWrapper::InstallWrapper(QObject* parent, |
364 | 22 const QString& path, const QStringList& choices): |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
23 QThread(parent), |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
24 mCertListFile(path), |
364 | 25 mChoices(choices) |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
26 { |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
27 } |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
28 |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
29 QFileInfo getCinstProcInfo() { |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
30 QFileInfo fi(QCoreApplication::applicationFilePath()); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
31 QDir myDir = fi.absoluteDir(); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
32 QString instProcName = "cinst"; |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
33 if (!fi.suffix().isEmpty()) { |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
34 instProcName += "." + fi.suffix(); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
35 } |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
36 return QFileInfo(myDir.absoluteFilePath(instProcName)); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
37 } |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
38 |
364 | 39 bool InstallWrapper::writeChoices(QTemporaryFile* choicesFile) const |
40 { | |
41 if (!choicesFile->open()) { | |
42 return false; | |
43 } | |
44 | |
45 foreach (const QString &b64data, mChoices) { | |
440
a7163018de2f
Fixed check on return value when trying to write temp file.
Raimund Renkert <rrenkert@intevation.de>
parents:
404
diff
changeset
|
46 if (choicesFile->write(b64data.toLatin1()) == -1) { |
364 | 47 return false; |
48 } | |
440
a7163018de2f
Fixed check on return value when trying to write temp file.
Raimund Renkert <rrenkert@intevation.de>
parents:
404
diff
changeset
|
49 if (choicesFile->write("\n") == -1) { |
364 | 50 return false; |
51 } | |
52 } | |
53 | |
54 choicesFile->close(); | |
55 | |
56 return true; | |
57 } | |
58 | |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
59 void InstallWrapper::run() |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
60 { |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
61 /* TODO: We need errorcodes here so that we can see if a user |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
62 * cancled the UAC elevation */ |
364 | 63 QTemporaryFile choicesFile; |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
64 QFileInfo cinstProcInfo = getCinstProcInfo(); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
65 |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
66 QString cinstFileName = QDir::toNativeSeparators( |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
67 getCinstProcInfo().absoluteFilePath()); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
68 |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
69 if (!cinstProcInfo.isExecutable()) { |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
70 emit error(tr("Could not find certificate installation process.")); |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
71 return; |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
72 } |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
73 |
364 | 74 if (!writeChoices(&choicesFile)) { |
75 emit error(tr("Failed to write temporary file.")); | |
76 return; | |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
77 } |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
78 |
364 | 79 #ifdef WIN32 |
80 /* QProcess on Windows uses CreateProcess but we have to | |
81 * use the runas shell command to get the UAC prompt if necessary. | |
82 * So we have to handle the process ourself. Starting with | |
83 * shell execute also means that we can not have stdout and stderr | |
84 * redirection. This is the reason we use command line parameters | |
85 * and not a pipe for communication. In debug mode the installer | |
86 * also makes use of output debug string. */ | |
87 DWORD retval = 0; | |
88 SHELLEXECUTEINFOW shExecInfo; | |
89 | |
90 memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW)); | |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
91 |
385
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
92 /* Windows needs each parameter packed in " */ |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
93 QString parameters = "\"list=" + mCertListFile + |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
94 "\" \"choices=" + choicesFile.fileName() + "\""; |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
95 |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
96 shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
97 shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
98 shExecInfo.lpVerb = L"runas"; |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
99 shExecInfo.lpFile = reinterpret_cast<LPCWSTR> (cinstFileName.utf16()); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
100 shExecInfo.lpParameters = reinterpret_cast<LPCWSTR> (parameters.utf16()); |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
101 |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
102 qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
103 |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
104 if (!ShellExecuteExW(&shExecInfo)) { |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
105 char* errmsg = getLastErrorMsg(); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
106 QString qerrmsg = QString::fromUtf8(errmsg); |
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
107 free(errmsg); |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
108 emit error(tr("Error executing process: %1").arg(qerrmsg)); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
109 return; |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
110 } |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
111 |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
112 retval = WaitForSingleObject(shExecInfo.hProcess, INSTALL_TIMEOUT); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
113 |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
114 if (retval != WAIT_OBJECT_0) { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
115 if (retval == WAIT_FAILED) { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
116 char* errmsg = getLastErrorMsg(); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
117 QString qerrmsg = QString::fromUtf8(errmsg); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
118 free(errmsg); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
119 emit error (tr("Error monitoring process: %1").arg(qerrmsg)); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
120 return; |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
121 } else { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
122 emit error (tr("Certificate installation timed out.")); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
123 return; |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
124 } |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
125 } |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
126 |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
127 if (GetExitCodeProcess(shExecInfo.hProcess, &retval)) { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
128 if (retval == STILL_ACTIVE) { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
129 qDebug() << "Process still running, huh.."; |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
130 } |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
131 } else { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
132 char* errmsg = getLastErrorMsg(); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
133 QString qerrmsg = QString::fromUtf8(errmsg); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
134 free(errmsg); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
135 emit error (tr("Failed to check process status: %1").arg(qerrmsg)); |
387
32309299bec9
Always return after error
Andre Heinecke <andre.heinecke@intevation.de>
parents:
385
diff
changeset
|
136 CloseHandle(shExecInfo.hProcess); |
32309299bec9
Always return after error
Andre Heinecke <andre.heinecke@intevation.de>
parents:
385
diff
changeset
|
137 return; |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
138 } |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
139 CloseHandle(shExecInfo.hProcess); |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
140 |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
141 if (retval != 0) { |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
142 /* TODO make this nicer */ |
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
143 emit error (tr("The process failed with return code. %1").arg(retval)); |
388
a507e5f1b999
Emit a signal if no errors happened during installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
387
diff
changeset
|
144 return; |
285
f23e0ccd5d14
Fix call to windows process.
Andre Heinecke <aheinecke@intevation.de>
parents:
256
diff
changeset
|
145 } |
364 | 146 #else /* WIN32 */ |
147 QProcess installerProcess; | |
148 installerProcess.setProgram(cinstProcInfo.absoluteFilePath()); | |
385
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
149 QStringList parameters; |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
150 |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
151 choicesFile.setAutoRemove(false); |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
152 parameters << "list=" + mCertListFile << "choices=" + choicesFile.fileName(); |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
153 installerProcess.setArguments(parameters); |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
154 |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
155 |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
156 qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
157 installerProcess.start(); |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
158 if (!installerProcess.waitForStarted() || |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
159 installerProcess.state() == QProcess::NotRunning) { |
364 | 160 emit error (tr("Failed to start installer process.")); |
161 return; | |
162 } | |
163 | |
164 installerProcess.waitForFinished(); | |
165 | |
166 if (installerProcess.exitStatus() == QProcess::CrashExit) { | |
167 /* Woops */ | |
385
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
168 emit error (tr("Failed to complete installation.")); |
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
169 return; |
364 | 170 } else if (installerProcess.exitStatus() != QProcess::NormalExit) { |
171 /* Can not Happen. there are only those two values but maybe | |
172 * qt changed.. */ | |
385
72487438a180
More user visible errors. Correct parameters for installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
364
diff
changeset
|
173 emit error (tr("Failed to complete installation.")); |
364 | 174 return; |
175 } | |
176 | |
177 if (installerProcess.exitCode() == 0) { | |
178 qDebug() << "output: " << installerProcess.readAllStandardOutput(); | |
179 } else { | |
180 /* TODO handle errors defined by errorcodes.h */ | |
181 qDebug() << "Installer Process returned: " << installerProcess.exitCode(); | |
182 qDebug() << "output: " << installerProcess.readAllStandardOutput(); | |
183 return; | |
184 } | |
185 #endif | |
388
a507e5f1b999
Emit a signal if no errors happened during installation.
Andre Heinecke <andre.heinecke@intevation.de>
parents:
387
diff
changeset
|
186 emit installationSuccessful(); |
256
84ae353688e0
Add installwrapper class to handle process communication
Andre Heinecke <aheinecke@intevation.de>
parents:
diff
changeset
|
187 } |