Use git-describe to determine release version
[cygwin-setup.git] / main.cc
blobe968d9320e34711e50daf6eddcf76972b948773c
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
3 * Copyright (c) 2003, Robert Collins <rbtcollins@hotmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * A copy of the GNU General Public License can be found at
11 * http://www.gnu.org/
13 * Written by DJ Delorie <dj@cygnus.com>
14 * Robert Collins <rbtcollins@hotmail.com>
19 /* OK, here's how this works. Each of the steps needed for install -
20 dialogs, downloads, installs - are in their own files and have some
21 "do_*" function (prototype in dialog.h) and a resource id (IDD_* or
22 IDD_S_* in resource.h) for that step. Each step is responsible for
23 selecting the next step! See the NEXT macro in dialog.h. Note
24 that the IDD_S_* ids are fake; those are for steps that don't
25 really have a controlling dialog (some have progress dialogs, but
26 those don't count, although they could). Replace the IDD_S_* with
27 IDD_* if you create a real dialog for those steps. */
29 #if 0
30 static const char *cvsid =
31 "\n%%% $Id$\n";
32 #endif
34 #undef _WIN32_WINNT
35 #define _WIN32_WINNT 0x0501
36 #include "win32.h"
37 #include <commctrl.h>
38 #include <shellapi.h>
39 #include "shlobj.h"
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include "resource.h"
44 #include "dialog.h"
45 #include "state.h"
46 #include "msg.h"
47 #include "find.h"
48 #include "mount.h"
49 #include "LogFile.h"
50 #include "setup_version.h"
52 #include "proppage.h"
53 #include "propsheet.h"
55 // Page class headers
56 #include "splash.h"
57 #include "AntiVirus.h"
58 #include "source.h"
59 #include "root.h"
60 #include "localdir.h"
61 #include "net.h"
62 #include "site.h"
63 #include "choose.h"
64 #include "prereq.h"
65 #include "threebar.h"
66 #include "desktop.h"
67 #include "postinstallresults.h"
69 #include "getopt++/GetOption.h"
70 #include "getopt++/BoolOption.h"
71 #include "getopt++/StringOption.h"
73 #include "Exception.h"
74 #include <stdexcept>
76 #include "UserSettings.h"
77 #include "SourceSetting.h"
78 #include "ConnectionSetting.h"
79 #include "KeysSetting.h"
81 #include <wincon.h>
82 #include <fstream>
84 #ifdef __MINGW64_VERSION_MAJOR
85 extern char **_argv;
86 #endif
88 bool is_64bit;
90 using namespace std;
92 HINSTANCE hinstance;
94 static StringOption Arch ("", 'a', "arch", "architecture to install (x86_64 or x86)", false);
95 static BoolOption UnattendedOption (false, 'q', "quiet-mode", "Unattended setup mode");
96 static BoolOption PackageManagerOption (false, 'M', "package-manager", "Semi-attended chooser-only mode");
97 static BoolOption NoAdminOption (false, 'B', "no-admin", "Do not check for and enforce running as Administrator");
98 static BoolOption WaitOption (false, 'W', "wait", "When elevating, wait for elevated child process");
99 static BoolOption HelpOption (false, 'h', "help", "print help");
101 static void inline
102 set_cout ()
104 HANDLE my_stdout = GetStdHandle (STD_OUTPUT_HANDLE);
105 if (my_stdout != INVALID_HANDLE_VALUE && GetFileType (my_stdout) != FILE_TYPE_UNKNOWN)
106 return;
108 if (AttachConsole ((DWORD) -1))
110 ofstream *conout = new ofstream ("conout$");
111 cout.rdbuf (conout->rdbuf ());
112 cout.flush ();
116 // Other threads talk to these pages, so we need to have it externable.
117 ThreeBarProgressPage Progress;
118 PostInstallResultsPage PostInstallResults;
120 static inline void
121 main_display ()
123 /* nondisplay classes */
124 LocalDirSetting localDir;
125 SourceSetting SourceSettings;
126 ConnectionSetting ConnectionSettings;
127 SiteSetting ChosenSites;
128 ExtraKeysSetting ExtraKeys;
130 SplashPage Splash;
131 AntiVirusPage AntiVirus;
132 SourcePage Source;
133 RootPage Root;
134 LocalDirPage LocalDir;
135 NetPage Net;
136 SitePage Site;
137 ChooserPage Chooser;
138 PrereqPage Prereq;
139 DesktopSetupPage Desktop;
140 PropSheet MainWindow;
142 Log (LOG_TIMESTAMP) << "Current Directory: " << local_dir << endLog;
144 // Initialize common controls
145 INITCOMMONCONTROLSEX icce = { sizeof (INITCOMMONCONTROLSEX),
146 ICC_WIN95_CLASSES };
147 InitCommonControlsEx (&icce);
149 // Initialize COM and ShellLink instance here. For some reason
150 // Windows 7 fails to create the ShellLink instance if this is
151 // done later, in the thread which actually creates the shortcuts.
152 extern IShellLink *sl;
153 CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
154 HRESULT res = CoCreateInstance (CLSID_ShellLink, NULL,
155 CLSCTX_INPROC_SERVER, IID_IShellLink,
156 (LPVOID *) & sl);
157 if (res)
159 char buf[256];
160 sprintf (buf, "CoCreateInstance failed with error 0x%x.\n"
161 "Setup will not be able to create Cygwin Icons\n"
162 "in the Start Menu or on the Desktop.", (int) res);
163 MessageBox (NULL, buf, "Cygwin Setup", MB_OK);
166 // Init window class lib
167 Window::SetAppInstance (hinstance);
169 // Create pages
170 Splash.Create ();
171 AntiVirus.Create ();
172 Source.Create ();
173 Root.Create ();
174 LocalDir.Create ();
175 Net.Create ();
176 Site.Create ();
177 Chooser.Create ();
178 Prereq.Create ();
179 Progress.Create ();
180 PostInstallResults.Create ();
181 Desktop.Create ();
183 // Add pages to sheet
184 MainWindow.AddPage (&Splash);
185 MainWindow.AddPage (&AntiVirus);
186 MainWindow.AddPage (&Source);
187 MainWindow.AddPage (&Root);
188 MainWindow.AddPage (&LocalDir);
189 MainWindow.AddPage (&Net);
190 MainWindow.AddPage (&Site);
191 MainWindow.AddPage (&Chooser);
192 MainWindow.AddPage (&Prereq);
193 MainWindow.AddPage (&Progress);
194 MainWindow.AddPage (&PostInstallResults);
195 MainWindow.AddPage (&Desktop);
197 // Create the PropSheet main window
198 MainWindow.Create ();
200 // Uninitalize COM
201 if (sl)
202 sl->Release ();
203 CoUninitialize ();
206 int WINAPI
207 WinMain (HINSTANCE h,
208 HINSTANCE hPrevInstance, LPSTR command_line, int cmd_show)
211 hinstance = h;
213 // Make sure the C runtime functions use the same codepage as the GUI
214 char locale[12];
215 snprintf(locale, sizeof locale, ".%u", GetACP());
216 setlocale(LC_ALL, locale);
218 char **_argv;
219 int argc;
220 for (argc = 0, _argv = __argv; *_argv; _argv++)
221 ++argc;
222 _argv = __argv;
224 try {
225 bool help_option = false;
226 bool invalid_option = false;
227 char cwd[MAX_PATH];
228 GetCurrentDirectory (MAX_PATH, cwd);
229 local_dir = std::string (cwd);
231 if (!GetOption::GetInstance ().Process (argc,_argv, NULL))
232 help_option = invalid_option = true;
233 else if (HelpOption)
234 help_option = true;
236 if (!((string) Arch).size ())
238 #ifdef __x86_64__
239 is_64bit = true;
240 #else
241 is_64bit = false;
242 #endif
244 else if (((string) Arch).find ("64") != string::npos)
245 is_64bit = true;
246 else if (((string) Arch).find ("32") != string::npos
247 || ((string) Arch).find ("x86") != string::npos)
248 is_64bit = false;
249 else
251 char buff[80 + ((string) Arch).size ()];
252 sprintf (buff, "Invalid option for --arch: \"%s\"",
253 ((string) Arch).c_str ());
254 fprintf (stderr, "*** %s\n", buff);
255 MessageBox (NULL, buff, "Invalid option", MB_ICONEXCLAMATION | MB_OK);
256 exit (1);
259 unattended_mode = PackageManagerOption ? chooseronly
260 : (UnattendedOption ? unattended : attended);
262 if (unattended_mode || help_option)
263 set_cout ();
265 /* Get System info */
266 OSVERSIONINFO version;
267 version.dwOSVersionInfoSize = sizeof version;
268 GetVersionEx (&version);
269 /* Initialize well known SIDs. We need the admin SID to test if we're
270 supposed to elevate. */
271 nt_sec.initialiseWellKnownSIDs ();
272 /* Check if we have to elevate. */
273 bool elevate = !help_option && version.dwMajorVersion >= 6
274 && !NoAdminOption && !nt_sec.isRunAsAdmin ();
276 /* Start logging only if we don't elevate. Same for setting default
277 security settings. */
278 LogSingleton::SetInstance (*LogFile::createLogFile ());
279 const char *sep = isdirsep (local_dir[local_dir.size () - 1])
280 ? "" : "\\";
281 /* Don't create log files for help output only. */
282 if (!elevate && !help_option)
284 Logger ().setFile (LOG_BABBLE, local_dir + sep + "setup.log.full",
285 false);
286 Logger ().setFile (0, local_dir + sep + "setup.log", true);
287 Log (LOG_PLAIN) << "Starting cygwin install, version "
288 << setup_version << endLog;
291 if (help_option)
293 if (invalid_option)
294 Log (LOG_PLAIN) << "\nError during option processing." << endLog;
295 Log (LOG_PLAIN) << "\nCommand Line Options:\n" << endLog;
296 GetOption::GetInstance ().ParameterUsage (Log (LOG_PLAIN));
297 Log (LOG_PLAIN) << endLog;
298 Logger ().exit (invalid_option ? 1 : 0, false);
300 else if (elevate)
302 char exe_path[MAX_PATH];
303 if (!GetModuleFileName(NULL, exe_path, ARRAYSIZE(exe_path)))
304 goto finish_up;
306 SHELLEXECUTEINFO sei = { sizeof(sei) };
307 sei.lpVerb = "runas";
308 sei.lpFile = exe_path;
309 sei.nShow = SW_NORMAL;
310 if (WaitOption)
311 sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
313 // Avoid another isRunAsAdmin check in the child.
314 std::string command_line_cs (command_line);
315 command_line_cs += " -";
316 command_line_cs += NoAdminOption.shortOption();
317 sei.lpParameters = command_line_cs.c_str ();
319 if (ShellExecuteEx(&sei))
321 /* Wait until child process is finished. */
322 if (WaitOption && sei.hProcess != NULL)
323 WaitForSingleObject (sei.hProcess, INFINITE);
325 Logger ().setExitMsg (IDS_ELEVATED);
326 Logger ().exit (0, false);
328 else
330 /* Set default DACL and Group. */
331 nt_sec.setDefaultSecurity ();
333 UserSettings Settings (local_dir);
334 main_display ();
335 Settings.save (); // Clean exit.. save user options.
336 if (rebootneeded)
337 Logger ().setExitMsg (IDS_REBOOT_REQUIRED);
338 Logger ().exit (rebootneeded ? IDS_REBOOT_REQUIRED : 0);
340 finish_up:
343 TOPLEVEL_CATCH("main");
345 // Never reached
346 return 0;