]> cygwin.com Git - cygwin-apps/setup.git/blob - root.cc
ccbd6ae309a56b7251cdec9df9917fb2997f1d97
[cygwin-apps/setup.git] / root.cc
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
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 *
14 */
15
16 /* The purpose of this file is to ask the user where they want the
17 root of the installation to be, and to ask whether the user prefers
18 text or binary mounts. */
19
20 #include "root.h"
21
22 #include "LogSingleton.h"
23
24 #include "win32.h"
25 #include <shlobj.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29
30 #include "ini.h"
31 #include "dialog.h"
32 #include "resource.h"
33 #include "state.h"
34 #include "msg.h"
35 #include "package_db.h"
36 #include "mount.h"
37 #include "propsheet.h"
38
39 #include "getopt++/StringOption.h"
40
41 StringOption RootOption ("", 'R', "root", IDS_HELPTEXT_ROOT, false);
42
43 static ControlAdjuster::ControlInfo RootControlsInfo[] = {
44 { IDC_ROOTDIR_GRP, CP_STRETCH, CP_TOP },
45 { IDC_ROOT_DIR, CP_STRETCH, CP_TOP },
46 { IDC_ROOT_BROWSE, CP_RIGHT, CP_TOP },
47
48 { IDC_INSTALLFOR_GRP, CP_STRETCH, CP_STRETCH },
49 { IDC_ROOT_SYSTEM, CP_LEFT, CP_TOP },
50 { IDC_ALLUSERS_TEXT, CP_STRETCH, CP_TOP },
51 { IDC_ROOT_USER, CP_LEFT, CP_BOTTOM },
52 { IDC_JUSTME_TEXT, CP_STRETCH, CP_BOTTOM },
53
54 {0, CP_LEFT, CP_TOP}
55 };
56
57 static int su[] = { IDC_ROOT_SYSTEM, IDC_ROOT_USER, 0 };
58
59 static std::string orig_root_dir;
60
61 void
62 RootPage::check_if_enable_next (HWND h)
63 {
64 DWORD ButtonFlags = PSWIZB_BACK;
65 // if there's something in the root dir box, and we have a scope, enable next
66 if (egetString (h, IDC_ROOT_DIR).size() && root_scope)
67 ButtonFlags |= PSWIZB_NEXT;
68 GetOwner ()->SetButtons (ButtonFlags);
69 }
70
71 static void
72 load_dialog (HWND h)
73 {
74 rbset (h, su, root_scope);
75 eset (h, IDC_ROOT_DIR, get_root_dir ());
76 }
77
78 static void
79 save_dialog (HWND h)
80 {
81 root_scope = rbget (h, su);
82 set_root_dir (egetString (h, IDC_ROOT_DIR));
83 }
84
85 static int CALLBACK
86 browse_cb (HWND h, UINT msg, LPARAM lp, LPARAM data)
87 {
88 switch (msg)
89 {
90 case BFFM_INITIALIZED:
91 if (get_root_dir ().size())
92 SendMessage (h, BFFM_SETSELECTION, TRUE, (LPARAM) get_root_dir ().c_str());
93 break;
94 }
95 return 0;
96 }
97
98 static void
99 browse (HWND h)
100 {
101 std::wstring title = LoadStringW(IDS_ROOT_BROWSE_TITLE);
102
103 wchar_t wname[MAX_PATH];
104 BROWSEINFOW bi;
105 memset (&bi, 0, sizeof (bi));
106 bi.hwndOwner = h;
107 bi.pszDisplayName = wname;
108 bi.lpszTitle = title.c_str();
109 bi.ulFlags = BIF_RETURNONLYFSDIRS;
110 bi.lpfn = browse_cb;
111
112 /* SHGetPathFromIDList doesn't handle path length > MAX_PATH. */
113 LPITEMIDLIST pidl;
114 pidl = SHBrowseForFolderW (&bi);
115 if (pidl)
116 {
117 CHAR name[MAX_PATH];
118 if (SHGetPathFromIDList (pidl, name))
119 eset (h, IDC_ROOT_DIR, name);
120 }
121 }
122
123 static int
124 directory_is_absolute ()
125 {
126 const std::string &r = get_root_dir ();
127 if (isalpha (r[0]) && r[1] == ':' && isdirsep (r[2]))
128 return 1;
129 return 0;
130 }
131
132 static int
133 directory_is_rootdir ()
134 {
135 const std::string &r = get_root_dir ();
136 size_t pos = r.find_first_of ("/\\");
137 if (pos != std::string::npos)
138 {
139 while (isdirsep (r[++pos]))
140 ;
141 if (r[pos])
142 return 0;
143 }
144 return 1;
145 }
146
147 static int
148 directory_has_spaces ()
149 {
150 if (std::string(get_root_dir()).find(' ') != std::string::npos)
151 return 1;
152 return 0;
153 }
154
155 static int
156 directory_contains_wrong_version (HWND h)
157 {
158 HANDLE fh;
159 std::string cygwin_dll = get_root_dir() + "\\bin\\cygwin1.dll";
160
161 /* Check if we have a cygwin1.dll. If not, this is a new install.
162 If yes, check if the target machine type of this setup version is the
163 same as the machine type of the install Cygwin DLL. If yes, just go
164 ahead. If not, show a message and indicate this to the caller.
165
166 If anything goes wrong reading the header of cygwin1.dll, we check
167 cygcheck.exe's binary type. This also covers the situation that the
168 installed cygwin1.dll is broken for some reason. */
169 fh = CreateFileA (cygwin_dll.c_str (), GENERIC_READ, FILE_SHARE_VALID_FLAGS,
170 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
171 if (fh != INVALID_HANDLE_VALUE)
172 {
173 DWORD read = 0;
174 struct {
175 LONG dos_header[32];
176 IMAGE_NT_HEADERS32 nt_header;
177 } hdr;
178
179 ReadFile (fh, &hdr, sizeof hdr, &read, NULL);
180 CloseHandle (fh);
181 if (read != sizeof hdr)
182 fh = INVALID_HANDLE_VALUE;
183 else
184 {
185 /* 32 bit setup and 32 bit inst? */
186 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386
187 && !is_64bit)
188 return 0;
189 /* 64 bit setup and 64 bit inst? */
190 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
191 && is_64bit)
192 return 0;
193 }
194 }
195 if (fh == INVALID_HANDLE_VALUE)
196 {
197 DWORD type;
198 std::string cygcheck_exe = get_root_dir() + "\\bin\\cygcheck.exe";
199
200 /* Probably new installation */
201 if (!GetBinaryType (cygcheck_exe.c_str (), &type))
202 {
203 is_new_install = true;
204 return 0;
205 }
206 /* 64 bit setup and 64 bit inst? */
207 if (type == SCS_32BIT_BINARY && !is_64bit)
208 return 0;
209 /* 32 bit setup and 32 bit inst? */
210 if (type == SCS_64BIT_BINARY && is_64bit)
211 return 0;
212 }
213
214 /* Forestall mixing. */
215 const char *setup_ver = is_64bit ? "64" : "32";
216 const char *inst_ver = is_64bit ? "32" : "64";
217 mbox (h, IDS_MIXED_BITNESS_ERROR, MB_OK,
218 setup_ver, inst_ver, is_64bit ? "x86" : "x86_64", inst_ver, setup_ver);
219 return 1;
220 }
221
222 bool
223 RootPage::OnMessageCmd (int id, HWND hwndctl, UINT code)
224 {
225 switch (id)
226 {
227
228 case IDC_ROOT_DIR:
229 case IDC_ROOT_SYSTEM:
230 case IDC_ROOT_USER:
231 check_if_enable_next (GetHWND ());
232 break;
233
234 case IDC_ROOT_BROWSE:
235 browse (GetHWND ());
236 break;
237 default:
238 return false;
239 }
240 return true;
241 }
242
243 RootPage::RootPage ()
244 {
245 sizeProcessor.AddControlInfo (RootControlsInfo);
246 }
247
248 bool
249 RootPage::Create ()
250 {
251 return PropertyPage::Create (IDD_ROOT);
252 }
253
254 void
255 RootPage::OnInit ()
256 {
257 if (((std::string)RootOption).size())
258 set_root_dir((std::string)RootOption);
259 if (!get_root_dir ().size())
260 read_mounts (std::string ());
261 orig_root_dir = get_root_dir();
262
263 if (!nt_sec.isRunAsAdmin())
264 {
265 // disable IDC_ROOT_SYSTEM if not running as admin
266 EnableWindow(GetDlgItem(IDC_ROOT_SYSTEM), FALSE);
267 root_scope = IDC_ROOT_USER;
268 }
269 else
270 {
271 set_default_root_scope();
272 }
273
274 load_dialog (GetHWND ());
275 }
276
277 void
278 RootPage::OnActivate ()
279 {
280 check_if_enable_next (GetHWND ());
281 }
282
283 bool
284 RootPage::wantsActivation() const
285 {
286 return (source != IDC_SOURCE_DOWNLOAD);
287 }
288
289 long
290 RootPage::OnNext ()
291 {
292 HWND h = GetHWND ();
293
294 save_dialog (h);
295
296 if (!directory_is_absolute ())
297 {
298 note (h, IDS_ROOT_ABSOLUTE);
299 return -1;
300 }
301 else if (get_root_dir() != orig_root_dir &&
302 directory_is_rootdir () && (IDNO == yesno (h, IDS_ROOT_SLASH)))
303 return -1;
304 else if (directory_has_spaces () && (IDNO == yesno (h, IDS_ROOT_SPACE)))
305 return -1;
306 else if (directory_contains_wrong_version (h))
307 return -1;
308
309 Log (LOG_PLAIN) << "root: " << get_root_dir ()
310 << (root_scope == IDC_ROOT_USER ? " user" : " system") << endLog;
311
312 if (root_scope == IDC_ROOT_SYSTEM)
313 nt_sec.setAdminGroup ();
314 else
315 nt_sec.resetPrimaryGroup ();
316
317 return 0;
318 }
319
320 long
321 RootPage::OnBack ()
322 {
323 HWND h = GetHWND ();
324
325 save_dialog (h);
326 return 0;
327 }
328
329 long
330 RootPage::OnUnattended ()
331 {
332 return OnNext();
333 }
This page took 0.058703 seconds and 6 git commands to generate.