Debugging: Add code to print backtrace for guest on SIGSEGV
[nativeclient.git] / tools / firefoxinstall.py
blob375b1d228ec4cad593d02e41fcac0b9e9c1bfe28
1 #!/usr/bin/python
2 # Copyright 2008, Google Inc.
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 # Note: If you change this script, make sure the wiki page is up to date:
33 # http://code.google.com/p/nativeclient/wiki/FilesInstalled
36 """Firefox installer for the NaCl developer release
38 A simple script for a NaCl developer to install the Firefox plugin
39 on a machine after a NaCl build from source. To be executed from the
40 root of the NaCl source tree.
42 """
44 import os
45 import platform
46 import shutil
47 import stat
48 import struct
49 import sys
52 # Is this script embedded in an installer?
53 # Set with a command line option (e.g. PKGINSTALL).
54 EMBEDDED = False
56 def Usage(progname):
57 print("""
58 USAGE:
59 %s PLATFORM_BASE=<platform_base>
61 You don't usually invoke this script directly.
62 Instead, you use SCons, with the following syntax:
63 ./scons [--prebuilt] firefox_install [DBG=1]
64 where:
65 --prebuilt means don't attempt to rebuild the plugin binaries
66 DBG=1 means install the debug version of the plugin
67 For example:
68 %s PLATFORM_BASE=.../native_client/scons-out/
69 is the same as
70 ./scons --prebuilt firefox_install
72 Note: by default the scons command will install the release version
73 of the plugin. In order to install the debug version, use:
74 ./scons --prebuilt firefox_install DBG=1
75 which is the same as
76 %s PLATFORM_BASE=.../native_client/scons-out/ MODE=1
78 In this case scons will take care of the command line args.
79 """ % (progname, progname, progname))
82 def FatalError(msg):
83 sys.stderr.write(msg)
84 sys.stderr.write("\n**** INSTALLATION FAILED.\n\n")
85 sys.exit(-1)
87 def CheckCondition(boolcond, emsg):
88 if boolcond: return
89 FatalError("Error:" + emsg + "\n")
91 def CheckFileExists(what, emsg):
92 if os.path.isfile(what): return
93 FatalError("Error: \"%s\" not found.\n%s\n" % (what, emsg))
95 def CheckDirExists(what, emsg):
96 if os.path.isdir(what): return
97 FatalError("Error: directory \"%s\" not found.\n%s\n" % (what, emsg))
99 def OkayToInstall():
100 # Can't be interactive if embedded.
101 if EMBEDDED:
102 return True
103 sys.stdout.write("Okay to continue? [y/n] ")
104 answer = sys.stdin.readline()
105 if answer[0] == "y":
106 print "Okay, you asked for it."
107 return True
108 else:
109 print "Okay, I'm bailing out then."
110 return False
112 def CopyFile(src, dst):
113 try:
114 print "copying", src, "to", dst, "..."
115 if os.path.isfile(dst): os.unlink(dst)
116 shutil.copy2(src, dst)
117 except OSError, err:
118 FatalError("ERROR: Could not copy %s to %s\n" % (src, dst))
120 def CopyDir(src, dst):
121 try:
122 print "copying directory", src, "to", dst, "..."
123 shutil.copytree(src, dst)
124 except OSError, err:
125 FatalError("ERROR: Could not copy %s to %s: %s\n" % (src, dst, err))
127 def CopyFilesOrDirs(src_dir, dst_dir, list):
128 for f in list:
129 name = os.path.join(src_dir, f)
130 if os.path.isfile(name):
131 CopyFile(name, dst_dir)
132 if os.path.isdir(name):
133 CopyDir(name, dst_dir)
135 def RemoveDir(dir):
136 try:
137 print "[Removing", dir, "...]"
138 shutil.rmtree(dir)
139 except OSError, err:
140 FatalError("ERROR: Could not remove %s\n" % (dir))
142 def TryMakedir(dirname):
143 if not os.path.isdir(dirname):
144 try:
145 print "[Creating", dirname, "...]"
146 os.makedirs(dirname)
147 except OSError, err:
148 FatalError("ERROR: Could not create %s\n" % dirname)
150 def RemoveFile(fname):
151 try:
152 print "[Removing", fname, "...]"
153 os.unlink(fname)
154 except OSError, err:
155 FatalError("ERROR: Could not remove %s\n" % fname)
157 def RemoveFilesOrDirs(dir, list):
158 for f in list:
159 name = os.path.join(dir, f)
160 if os.path.isfile(name):
161 RemoveFile(name)
162 if os.path.isdir(name):
163 RemoveDir(name)
165 def GetFromStaging(PLATFORM_BASE, what):
166 # Try local version in case we're an installer and all is "right here!"
167 if EMBEDDED:
168 localversion = os.path.join(PLATFORM_BASE, what)
169 if os.path.exists(localversion):
170 return localversion
171 return os.path.join(PLATFORM_BASE, "staging", what)
173 def PrintStars():
174 print "*********************************************************************"
176 def GetPluginDir():
177 pl = sys.platform
178 if pl in ['linux', 'linux2']:
179 return os.path.expandvars("$HOME/.mozilla/plugins")
180 if pl in ['darwin', 'mac']:
181 return os.path.expanduser(os.path.join("~", "Library", "Internet Plug-Ins"))
182 elif pl in ['win32', 'cygwin', 'win', 'windows']:
183 return os.path.join(os.getenv('PROGRAMFILES'), "Mozilla Firefox", "plugins")
184 else:
185 FatalError("Unknown platform %s" % pl)
187 def GetFilesToCopy():
188 pl = sys.platform
189 if pl in ['linux', 'linux2']:
190 return ["libnpGoogleNaClPlugin.so", "sel_ldr", "sel_ldr_bin", "sel_mon", "sel_ldr_bin.trace"]
191 if pl in ['darwin', 'mac']:
192 return ["npGoogleNaClPlugin.bundle"]
193 elif pl in ['win32', 'cygwin', 'win', 'windows']:
194 return ["npGoogleNaClPlugin.dll", "sel_ldr.exe"]
195 else:
196 FatalError("Unknown platform %s" % pl)
198 def InstallSuccess(sel_ldr):
199 PrintStars()
200 print "* You have successfully installed the NaCl Firefox plugin."
201 print "* As a self-test, please confirm you can run"
202 print "* ", sel_ldr
203 print "* from a shell/command prompt. With no args you should see"
204 print "* No nacl file specified"
205 print "* on Linux or Mac and no output on Windows."
206 PrintStars()
208 def RunningOn64BitSystem():
209 if (8 == len(struct.pack('P',0))):
210 return True
211 return False
213 def Linux_install(PLATFORM_BASE):
214 PLUGINDIR = GetPluginDir()
215 PLUGIN = os.path.join(PLATFORM_BASE, "staging", "libnpGoogleNaClPlugin.so")
216 SEL_LDR = GetFromStaging(PLATFORM_BASE, "sel_ldr")
217 SEL_LDR_SANDBOX = GetFromStaging(PLATFORM_BASE, "sel_ldr.trace")
218 SEL_LDR_SH = os.path.join(PLATFORM_BASE, "../../tools/sel_ldr.bash")
219 LIBSDL = GetFromStaging(PLATFORM_BASE, "libSDL-1.2.so.0")
220 SEL_LDR_INSTALLED_AS = os.path.join(PLUGINDIR, "sel_ldr_bin")
221 SEL_LDR_SH_INSTALLED_AS = os.path.join(PLUGINDIR, "sel_ldr")
222 SEL_LDR_SANDBOX_INSTALLED_AS = os.path.join(PLUGINDIR, "sel_ldr_bin.trace")
223 SDL_INSTALLED_AS = os.path.join(PLUGINDIR, "libSDL-1.2.so.0")
224 SEL_MON = GetFromStaging(PLATFORM_BASE, "sel_mon")
226 # Check that all source and destination files/directories exist
227 CheckFileExists(SEL_LDR, "Have you built NaCl yet?")
228 CheckFileExists(PLUGIN, "Have you built NaCl yet?")
229 CheckFileExists(LIBSDL, "Have you built NaCl yet?")
230 CheckFileExists("/bin/bash", "No /bin/bash? NaCl needs this to launch sel_ldr")
232 # Tell the user what we're going to do
233 print "This script will install"
234 print PLUGIN, ",", LIBSDL, "and", SEL_LDR, "in", PLUGINDIR
235 if not OkayToInstall():
236 sys.exit(0)
238 # do the deed...
239 TryMakedir(PLUGINDIR)
240 CopyFile(PLUGIN, PLUGINDIR)
241 if RunningOn64BitSystem():
242 # Call the wrapper on 64-bit Linux
243 print '64bit system detected running nspluginwrapper'
244 cmd = 'nspluginwrapper -i %s' % os.path.join(PLUGINDIR,
245 os.path.basename(PLUGIN))
246 print cmd
247 os.system(cmd)
248 CopyFile(SEL_MON, PLUGINDIR)
249 # avoid installing libSDL twice
250 if not os.path.isfile(SDL_INSTALLED_AS):
251 CopyFile(LIBSDL, SDL_INSTALLED_AS)
252 CopyFile(SEL_LDR, SEL_LDR_INSTALLED_AS)
253 CopyFile(SEL_LDR_SH, SEL_LDR_SH_INSTALLED_AS)
254 CopyFile(SEL_LDR_SANDBOX, SEL_LDR_SANDBOX_INSTALLED_AS)
255 os.chmod(SEL_LDR_SH_INSTALLED_AS, stat.S_IRUSR | stat.S_IXUSR | stat.S_IWUSR)
256 InstallSuccess(os.path.join(PLUGINDIR, "sel_ldr"))
258 def Windows_install(PLATFORM_BASE):
259 PLUGINDIR = GetPluginDir()
260 SEL_LDR = GetFromStaging(PLATFORM_BASE, "sel_ldr.exe")
261 SDL_DLL = GetFromStaging(PLATFORM_BASE, "SDL.dll")
262 PLUGIN = os.path.join(PLATFORM_BASE, "staging", "npGoogleNaClPlugin.dll")
264 # Check that all source and destination files/directories exist
265 CheckFileExists(SEL_LDR, "Have you built NaCl yet?")
266 CheckFileExists(SDL_DLL, "Have you built NaCl yet?")
267 CheckFileExists(PLUGIN, "Have you built NaCl yet?")
268 CheckDirExists(PLUGINDIR, "I don't know where to install browser plugins.")
270 # Tell the user what we're going to do
271 print "This script will install"
272 print PLUGIN, ",", SEL_LDR, "and", SDL_DLL
273 print "in", PLUGINDIR
274 if not OkayToInstall():
275 sys.exit(0)
277 # do the deed...
278 TryMakedir(PLUGINDIR)
279 CopyFile(SEL_LDR, PLUGINDIR)
280 CopyFile(SDL_DLL, PLUGINDIR)
281 CopyFile(PLUGIN, PLUGINDIR)
282 InstallSuccess(os.path.join(PLUGINDIR, "sel_ldr.exe"))
284 def MacNeedsSDL(SDLDEST):
285 SDLPath = None
286 if os.path.isdir("/Library/Frameworks/SDL.framework"):
287 SDLPath = "/Library/Frameworks/SDL.framework"
288 elif os.path.isdir(SDLDEST):
289 SDLPath = SDLDEST
290 else:
291 return True
293 print "*"
294 print "* It looks like SDL is already installed as"
295 print "* ", SDLPath
296 print "* For Native Client we recommend SDL Version 1.2.13"
297 print "* Please make sure your SDL version is compatible"
298 print "* with Native Client."
299 print "*"
300 return False
303 def Mac_install(PLATFORM_BASE):
304 PLUGINDIR = GetPluginDir()
305 BUNDLEDIR = os.path.join(PLUGINDIR, "npGoogleNaClPlugin.bundle")
306 SEL_LDR = GetFromStaging(PLATFORM_BASE, "sel_ldr")
308 # Local versions in case we're running in an installer (not from the
309 # source tree) and everything is in one spot
310 BUNDLE = None
311 if EMBEDDED:
312 localversion = os.path.join(PLATFORM_BASE, "npGoogleNaClPlugin.bundle")
313 if os.path.exists(localversion):
314 BUNDLE = localversion
315 if not BUNDLE:
316 BUNDLE = os.path.join(PLATFORM_BASE, "staging", "npGoogleNaClPlugin.bundle")
318 SDLFRAMEWORK = None
319 if EMBEDDED:
320 localversion = os.path.join(PLATFORM_BASE, "SDL.framework")
321 if os.path.exists(localversion):
322 SDLFRAMEWORK = localversion
323 if not SDLFRAMEWORK:
324 SDLFRAMEWORK = os.path.join(PLATFORM_BASE, "Frameworks", "SDL.framework")
325 FRAMEWORKS = os.path.expanduser(os.path.join("~", "Library", "Frameworks"))
326 SDLDEST = os.path.join(FRAMEWORKS, "SDL.framework")
327 SEL_LDR_DIR = os.path.join(BUNDLEDIR, "Contents", "Resources")
329 # Check that all source and destination files/directories exist
330 CheckDirExists(BUNDLE, "Have you built NaCl yet?")
331 CheckDirExists(SDLFRAMEWORK, "Have you built NaCl yet?")
332 CheckFileExists(os.path.join(BUNDLE,
333 "Contents", "MacOS", "npGoogleNaClPlugin"),
334 "Have you built NaCl yet?")
335 CheckFileExists(SEL_LDR, "Have you built NaCl yet?")
336 TryMakedir(PLUGINDIR)
338 # Tell the user what we're going to do
339 print "This script will install:"
340 print " ", BUNDLE, "in", BUNDLEDIR
341 print " ", SEL_LDR, "in", SEL_LDR_DIR
342 print "and"
343 print SDLFRAMEWORK, "in", SDLDEST
344 if not OkayToInstall():
345 sys.exit(0)
347 # do the deed...
348 if os.path.isdir(BUNDLEDIR):
349 RemoveDir(BUNDLEDIR)
351 CopyDir(BUNDLE, BUNDLEDIR)
352 if MacNeedsSDL(SDLDEST):
353 if not os.path.isdir(FRAMEWORKS):
354 os.makedirs(FRAMEWORKS)
355 CopyDir(SDLFRAMEWORK, SDLDEST)
356 CopyFile(SEL_LDR, SEL_LDR_DIR)
357 InstallSuccess(os.path.join(SEL_LDR_DIR, "sel_ldr"))
359 def ParseArgv(argv):
360 args = {}
361 for arg in argv[1:]:
362 if (arg.find("=") < 0):
363 Usage(argv[0])
364 name, value = arg.split("=")
365 print("%s=%s" % (name, value))
366 args[name] = value
367 # require PLATFORM_BASE (or PKGINSTALL) to be set
368 if ("PLATFORM_BASE" not in args and "PKGINSTALL" not in args
369 and "BACKUP" not in args and "RESTORE" not in args):
370 return None
371 if "PKGINSTALL" in args:
372 global EMBEDDED
373 EMBEDDED = True
374 if "MODE" not in args: args["MODE"] = '0'
375 if "BACKUP" not in args: args["BACKUP"] = '0'
376 if "RESTORE" not in args: args["RESTORE"] = '0'
377 return args
379 def GetTmpDirectory():
380 pl = sys.platform
381 if pl in ['linux', 'linux2', 'darwin', 'mac']:
382 tmp_dir = '/tmp/nacl'
383 elif pl in ['win32', 'cygwin', 'win', 'windows']:
384 os_tmp = os.getenv('TMP')
385 tmp_dir = os.path.join(os_tmp, 'nacl')
386 else:
387 FatalError("Backup/Restore cannot continue. Unknown platform %s" % pl)
388 return tmp_dir
390 def Backup():
391 tmp_dir = GetTmpDirectory()
392 plugin_dir = GetPluginDir()
393 files_to_copy = GetFilesToCopy()
395 if os.path.isdir(tmp_dir):
396 RemoveFilesOrDirs(tmp_dir, files_to_copy)
397 else:
398 # If for some reason there is a file with the same name.
399 if os.path.isfile(tmp_dir):
400 RemoveFile(tmp_dir)
401 TryMakedir(tmp_dir)
403 if os.path.exists(plugin_dir):
404 CopyFilesOrDirs(plugin_dir, tmp_dir, files_to_copy)
406 def Restore():
407 tmp_dir = GetTmpDirectory()
408 plugin_dir = GetPluginDir()
409 files_to_copy = GetFilesToCopy()
411 if os.path.exists(plugin_dir):
412 RemoveFilesOrDirs(plugin_dir, files_to_copy)
414 if os.path.exists(tmp_dir):
415 CopyFilesOrDirs(tmp_dir, plugin_dir, files_to_copy)
416 RemoveFilesOrDirs(tmp_dir, files_to_copy)
418 def main(argv):
419 args = ParseArgv(argv)
420 if args is None:
421 Usage(argv[0])
422 return -1
424 if args["BACKUP"] == '1':
425 Backup()
426 return 0
428 if args["RESTORE"] == '1':
429 Restore()
430 return 0
432 if args["MODE"] == '1':
433 mode = 'dbg-'
434 else:
435 mode = 'opt-'
437 pl = sys.platform
438 if pl in ['linux', 'linux2']:
439 Linux_install(args["PLATFORM_BASE"] + mode + 'linux')
440 elif pl in ['win32', 'cygwin', 'win', 'windows']:
441 Windows_install(args["PLATFORM_BASE"] + mode + 'win')
442 elif pl in ['darwin', 'mac']:
443 if os.uname()[-1] != 'i386':
444 FatalError('Cannot install on PPC Macs.')
445 if "PKGINSTALL" in args:
446 Mac_install(args["PKGINSTALL"])
447 else:
448 Mac_install(args["PLATFORM_BASE"] + mode + 'mac')
449 else:
450 print "Install cannot continue. Unknown platform %s" % pl
451 Usage(argv[0])
452 return -1
454 PLUGINDEMO = os.path.join("scons-out", "nacl", "staging", "index.html")
455 print "* To test this installation also try the test links on the page"
456 print "* ", PLUGINDEMO
457 PrintStars()
458 return 0
460 if '__main__' == __name__:
461 sys.exit(main(sys.argv))