README: document some recent changes in the build environment
[cygwin-setup.git] / root.cc
blob247926a5256ee2945220fd8584d6389da1530643
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by DJ Delorie <dj@cygnus.com>
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. */
20 #if 0
21 static const char *cvsid =
22 "\n%%% $Id$\n";
23 #endif
25 #include "root.h"
27 #include "LogSingleton.h"
29 #include "win32.h"
30 #include <shlobj.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
35 #include "ini.h"
36 #include "dialog.h"
37 #include "resource.h"
38 #include "state.h"
39 #include "msg.h"
40 #include "package_db.h"
41 #include "mount.h"
43 #include "getopt++/StringOption.h"
45 using namespace std;
47 StringOption RootOption ("", 'R', "root", "Root installation directory", false);
49 static ControlAdjuster::ControlInfo RootControlsInfo[] = {
50 { IDC_ROOTDIR_GRP, CP_STRETCH, CP_TOP },
51 { IDC_ROOT_DIR, CP_STRETCH, CP_TOP },
52 { IDC_ROOT_BROWSE, CP_RIGHT, CP_TOP },
54 { IDC_INSTALLFOR_GRP, CP_STRETCH, CP_STRETCH },
55 { IDC_ROOT_SYSTEM, CP_LEFT, CP_TOP },
56 { IDC_ALLUSERS_TEXT, CP_STRETCH, CP_TOP },
57 { IDC_ROOT_USER, CP_LEFT, CP_BOTTOM },
58 { IDC_JUSTME_TEXT, CP_STRETCH, CP_BOTTOM },
60 {0, CP_LEFT, CP_TOP}
63 static int su[] = { IDC_ROOT_SYSTEM, IDC_ROOT_USER, 0 };
65 static string orig_root_dir;
67 static void
68 check_if_enable_next (HWND h)
70 EnableWindow (GetDlgItem (h, IDOK),
71 egetString (h, IDC_ROOT_DIR).size() && root_scope);
74 static void
75 load_dialog (HWND h)
77 rbset (h, su, root_scope);
78 eset (h, IDC_ROOT_DIR, get_root_dir ());
79 check_if_enable_next (h);
82 static void
83 save_dialog (HWND h)
85 root_scope = rbget (h, su);
86 set_root_dir (egetString (h, IDC_ROOT_DIR));
89 static int CALLBACK
90 browse_cb (HWND h, UINT msg, LPARAM lp, LPARAM data)
92 switch (msg)
94 case BFFM_INITIALIZED:
95 if (get_root_dir ().size())
96 SendMessage (h, BFFM_SETSELECTION, TRUE, (LPARAM) get_root_dir ().c_str());
97 break;
99 return 0;
102 static void
103 browse (HWND h)
105 BROWSEINFO bi;
106 /* SHGetPathFromIDList doesn't handle path length > MAX_PATH. */
107 CHAR name[MAX_PATH];
108 LPITEMIDLIST pidl;
109 memset (&bi, 0, sizeof (bi));
110 bi.hwndOwner = h;
111 bi.pszDisplayName = name;
112 bi.lpszTitle = "Select an installation root directory";
113 bi.ulFlags = BIF_RETURNONLYFSDIRS;
114 bi.lpfn = browse_cb;
115 pidl = SHBrowseForFolder (&bi);
116 if (pidl)
118 if (SHGetPathFromIDList (pidl, name))
119 eset (h, IDC_ROOT_DIR, name);
123 static int
124 directory_is_absolute ()
127 const char *r = get_root_dir ().c_str();
128 if (isalpha (r[0]) && r[1] == ':' && (r[2] == '\\' || r[2] == '/'))
130 return 1;
132 return 0;
135 static int
136 directory_is_rootdir ()
139 for (const char *c = get_root_dir().c_str(); *c; c++)
140 if (isdirsep (c[0]) && c[1] && !isdirsep (c[1]))
141 return 0;
142 return 1;
145 static int
146 directory_has_spaces ()
148 if (std::string(get_root_dir()).find(' ') != std::string::npos)
149 return 1;
150 return 0;
153 static int
154 directory_contains_wrong_version (HWND h)
156 HANDLE fh;
157 char text[512];
158 std::string cygwin_dll = get_root_dir() + "\\bin\\cygwin1.dll";
160 /* Check if we have a cygwin1.dll. If not, this is a new install.
161 If yes, check if the target machine type of this setup version is the
162 same as the machine type of the install Cygwin DLL. If yes, just go
163 ahead. If not, show a message and indicate this to the caller.
165 If anything goes wrong reading the header of cygwin1.dll, we check
166 cygcheck.exe's binary type. This also covers the situation that the
167 installed cygwin1.dll is broken for some reason. */
168 fh = CreateFileA (cygwin_dll.c_str (), GENERIC_READ, FILE_SHARE_VALID_FLAGS,
169 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
170 if (fh != INVALID_HANDLE_VALUE)
172 DWORD read = 0;
173 struct {
174 LONG dos_header[32];
175 IMAGE_NT_HEADERS32 nt_header;
176 } hdr;
178 ReadFile (fh, &hdr, sizeof hdr, &read, NULL);
179 CloseHandle (fh);
180 if (read != sizeof hdr)
181 fh = INVALID_HANDLE_VALUE;
182 else
184 /* 32 bit setup and 32 bit inst? */
185 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386
186 && !is_64bit)
187 return 0;
188 /* 64 bit setup and 64 bit inst? */
189 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
190 && is_64bit)
191 return 0;
194 if (fh == INVALID_HANDLE_VALUE)
196 DWORD type;
197 std::string cygcheck_exe = get_root_dir() + "\\bin\\cygcheck.exe";
199 /* Probably new installation */
200 if (!GetBinaryType (cygcheck_exe.c_str (), &type))
201 return 0;
202 /* 64 bit setup and 64 bit inst? */
203 if (type == SCS_32BIT_BINARY && !is_64bit)
204 return 0;
205 /* 32 bit setup and 32 bit inst? */
206 if (type == SCS_64BIT_BINARY && is_64bit)
207 return 0;
210 /* Forestall mixing. */
211 const char *setup_ver = is_64bit ? "64" : "32";
212 const char *inst_ver = is_64bit ? "32" : "64";
213 snprintf (text, sizeof text,
214 "You're trying to install a %s bit version of Cygwin into a directory\n"
215 "containing a %s bit version of Cygwin. Continuing to do so would\n"
216 "break the existing installation.\n\n"
217 "Either run http://cygwin.com/setup-%s.exe to update your\n"
218 "existing %s bit installation of Cygwin, or choose another directory\n"
219 "for your %s bit installation.",
220 setup_ver, inst_ver,
221 is_64bit ? "x86" : "x86_64",
222 inst_ver, setup_ver);
223 MessageBox (h, text, "Target CPU mismatch", MB_OK);
224 return 1;
227 bool
228 RootPage::OnMessageCmd (int id, HWND hwndctl, UINT code)
230 switch (id)
233 case IDC_ROOT_DIR:
234 case IDC_ROOT_SYSTEM:
235 case IDC_ROOT_USER:
236 check_if_enable_next (GetHWND ());
237 break;
239 case IDC_ROOT_BROWSE:
240 browse (GetHWND ());
241 break;
242 default:
243 return false;
245 return true;
248 RootPage::RootPage ()
250 sizeProcessor.AddControlInfo (RootControlsInfo);
253 bool
254 RootPage::Create ()
256 return PropertyPage::Create (IDD_ROOT);
259 void
260 RootPage::OnInit ()
262 if (((string)RootOption).size())
263 set_root_dir((string)RootOption);
264 if (!get_root_dir ().size())
265 read_mounts (std::string ());
266 orig_root_dir = get_root_dir();
267 load_dialog (GetHWND ());
270 bool
271 RootPage::wantsActivation() const
273 return (source != IDC_SOURCE_DOWNLOAD);
276 long
277 RootPage::OnNext ()
279 HWND h = GetHWND ();
281 save_dialog (h);
283 if (!directory_is_absolute ())
285 note (h, IDS_ROOT_ABSOLUTE);
286 return -1;
288 else if (get_root_dir() != orig_root_dir &&
289 directory_is_rootdir () && (IDNO == yesno (h, IDS_ROOT_SLASH)))
290 return -1;
291 else if (directory_has_spaces () && (IDNO == yesno (h, IDS_ROOT_SPACE)))
292 return -1;
293 else if (directory_contains_wrong_version (h))
294 return -1;
296 Log (LOG_PLAIN) << "root: " << get_root_dir ()
297 << (root_scope == IDC_ROOT_USER ? " user" : " system") << endLog;
299 return 0;
302 long
303 RootPage::OnBack ()
305 HWND h = GetHWND ();
307 save_dialog (h);
308 return 0;
311 long
312 RootPage::OnUnattended ()
314 return OnNext();