root/freevo/freevo

Revision 1865, 16.7 kB (checked in by duncan, 2 months ago)

Added the generation of a debug script when "freevo -d" is executed
Changed "freevo -d -d" to write the gdb debug script to the current directory

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/env python
2# -*- coding: iso-8859-1 -*-
3# vim:tabstop=4:softtabstop=4:shiftwidth=4:expandtab:filetype=python:
4# -----------------------------------------------------------------------
5# freevo - the main entry point to the whole suite of applications
6# -----------------------------------------------------------------------
7# $Id$
8#
9# Notes: This is a rewrite of the old shell script in Python
10# Todo:
11#
12# -----------------------------------------------------------------------
13# Freevo - A Home Theater PC framework
14# Copyright (C) 2003 Krister Lagerstrom, et al.
15# Please see the file freevo/Docs/CREDITS for a complete list of authors.
16#
17# This program is free software; you can redistribute it and/or modify
18# it under the terms of the GNU General Public License as published by
19# the Free Software Foundation; either version 2 of the License, or
20# (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful, but
23# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
24# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
25# Public License for more details.
26#
27# You should have received a copy of the GNU General Public License along
28# with this program; if not, write to the Free Software Foundation, Inc.,
29# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30#
31# -----------------------------------------------------------------------
32
33import os
34import sys
35import time
36import popen2
37
38from stat import *
39from signal import *
40
41
42cmdfile = None
43def _debug_(message, level=1):
44    global debug
45    if debug >= level:
46        print message
47
48
49def _gdb_script_(message):
50    global debug
51    global cmdfile
52    if debug < 1:
53        return
54    print >>cmdfile, message
55
56
57def show_help():
58    """
59    show how to use this script
60    """
61    helper_list = ''
62    for helper in os.listdir(os.environ['FREEVO_HELPERS']):
63        if helper.endswith('.py') and not helper == '__init__.py':
64            helper_list += '  ' + helper[:-3] + '\n'
65
66    print '''\
67freevo [ script | options]
68options:
69  -fs            start freevo in a new x session in full-screen
70  --doc          create api documentation (for developers)
71  --trace        activate full trace (useful for debugging)
72  --profile      activate cProfile and write stats to /tmp
73  setup          run freevo setup to scan your environment
74  start          start freevo as daemon in background
75  stop           stop the current freevo process
76
77freevo can start the following scripts, use --help on these
78scripts to get more informations about options.
79
80%s
81
82Example: freevo imdb --help"
83         freevo webserver start"
84
85You can also create a symbolic link to freevo with the name of the
86script you want to execute. E.g. put a link imdb pointing to freevo
87in your path to access the imdb helper script
88
89Example: ln -s /path/to/freevo imdb
90         imdb --help
91
92Before running freevo the first time, you need to run \'freevo setup\'
93After that, you can run freevo without parameter.
94    ''' % helper_list
95    sys.exit(0)
96
97
98def get_python(check_freevo):
99    """
100    get the newest version of python [ with freevo installed ]
101    """
102    _debug_('version=%r' % (sys.version)) 
103    if sys.hexversion >= 0x02040000:
104        # python seems to be ok
105        search = ('python', 'python2')
106    elif sys.hexversion >= 0x02030000:
107        # try python2.4, else take python
108        search = ('python2.4', 'python')
109    else:
110        # python is too old, try to find python2.4 or python2
111        search = ('python2.4', 'python2')
112
113    for python in search:
114        for path in os.environ['PATH'].split(':'):
115            if os.path.isfile(os.path.join(path, python)):
116                # we found the binary for python
117                if not check_freevo:
118                    # return if we don't check for an installed version
119                    # of freevo
120                    _debug_('python=%r' % (python)) 
121                    return python
122
123                # try to import freevo with this python and get
124                # the path
125                cmd = '%s -c "import freevo; print freevo.__path__[0]"' % python
126                child = popen2.Popen4(cmd)
127                while 1:
128                    data = child.fromchild.readline()
129                    if not data:
130                        break
131                    if os.path.isdir(data[:-1]):
132                        # ok, found it, close child and return
133                        child.wait()
134                        child.fromchild.close()
135                        if child.childerr:
136                            child.childerr.close()
137                        child.tochild.close()
138                        _debug_('python=%r data=%r' % (python, data[:-1])) 
139                        return python, data[:-1]
140
141                child.wait()
142                child.fromchild.close()
143                if child.childerr:
144                    child.childerr.close()
145                child.tochild.close()
146
147    # nothing found? That's bad!
148    if check_freevo:
149        _debug_('python=%r data=%r' % (None, None))
150        return None, None
151    return None
152
153
154def getpid(name, arg):
155    """
156    get pid of running 'name'
157    """
158    _debug_('getpid(name=%r, arg=%r)' % (name, arg))
159    for fname in ('/var/run/' + name  + '-%s.pid' % os.getuid(),
160                  '/tmp/' + name + '-%s.pid' % os.getuid()):
161        if os.path.isfile(fname):
162            f = open(fname)
163            try:
164                pid = int(f.readline()[:-1])
165            except ValueError:
166                # file does not contain a number
167                _debug_('fname=%r pid=%r' % (fname, 0)) 
168                return fname, 0
169            f.close()
170
171            proc = '/proc/' + str(pid) + '/cmdline'
172            # FIXME: BSD support missing here
173            try:
174                if os.path.isfile(proc):
175                    f = open(proc)
176                    proc_arg = f.readline().split('\0')[:-1]
177                    f.close()
178                else:
179                    # process not running
180                    _debug_('fname=%r pid=%r' % (fname, 0)) 
181                    return fname, 0
182
183            except (OSError, IOError):
184                # running, but not freevo (because not mine)
185                _debug_('fname=%r pid=%r' % (fname, 0)) 
186                return fname, 0
187
188            if '-OO' in proc_arg:
189                proc_arg.remove('-OO')
190
191            if proc_arg and ((arg[0].find('runapp') == -1 and \
192                len(proc_arg)>2 and arg[1] != proc_arg[1]) or \
193                len(proc_arg)>3 and arg[2] != proc_arg[2]):
194                # different proc I guess
195                try:
196                    os.unlink(fname)
197                except OSError:
198                    pass
199                _debug_('fname=%r pid=%r' % (fname, 0)) 
200                return fname, 0
201            _debug_('fname=%r pid=%r' % (fname, pid)) 
202            return fname, pid
203    _debug_('fname=%r pid=%r' % (fname, 0)) 
204    return fname, 0
205
206
207def stop(name, arg):
208    """
209    stop running process 'name'
210    """
211    fname, pid = getpid(name, arg)
212    if not pid:
213        _debug_('cannot kill %r no pid' % (name))
214        return 0
215    try:
216        for signal in (SIGINT, SIGTERM, SIGKILL):
217            try:
218                _debug_('trying to kill %r pid=%r with signal=%r' % (name, pid, signal))
219                os.kill(pid, signal)
220                for i in range(10):
221                    if getpid(name, arg)[1] == 0:
222                        _debug_('killed %r pid=%r with signal=%r (%r)' % (name, pid, signal, i))
223                        break
224                    time.sleep(0.1)
225
226            except OSError, e:
227                _debug_('kill(pid=%r signal=%r): %s' % (pid, signal, e))
228                pass
229            if getpid(name, arg)[1] == 0:
230                return 1
231        return 0
232    finally:
233        try:
234            os.unlink(fname)
235            _debug_('%s removed' % (fname))
236        except OSError, e:
237            _debug_('%s NOT removed' % (fname))
238
239
240def start(name, arg, bg, store=1):
241    """
242    start a process
243    """
244    global cmdfile, debug
245    _debug_('start(name=%r, arg=%r, bg=%r, store=%r)' % (name, arg, bg, store))
246    if debug >= 2:
247        _gdb_script_('cat > freevo-gdb << _END_')
248        _gdb_script_('b main')
249        _gdb_script_('r %s' % ' '.join(arg[1:]))
250        _gdb_script_('_END_')
251        _gdb_script_('gdb -x freevo-gdb %s' % (arg[0]))
252    elif debug >= 1:
253        _gdb_script_('%s -m pdb src/main.py' % (arg[0]))
254    if cmdfile:
255        cmdfile.close()
256        os.chmod(cmdfile.name, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
257
258    pid = os.fork()
259    if pid:
260        if store:
261            try:
262                f = open('/var/run/' + name + '-%s.pid' % os.getuid(), 'w')
263            except (OSError, IOError):
264                f = open('/tmp/' + name + '-%s.pid' % os.getuid(), 'w')
265
266            f.write(str(pid)+'\n')
267            f.close()
268
269        if not bg:
270            try:
271                os.waitpid(pid, 0)
272            except KeyboardInterrupt:
273                os.kill(pid, SIGTERM)
274                try:
275                    os.waitpid(pid, 0)
276                except KeyboardInterrupt:
277                    pass
278                if store and os.path.isfile(f.name):
279                    os.unlink(f.name)
280    else:
281        os.execvp(arg[0], arg)
282
283#--------------------------------------------------------------------------------
284# Main block
285#--------------------------------------------------------------------------------
286debug = 0
287while '--debug' in sys.argv or '-d' in sys.argv:
288    debug += 1
289    if '--debug' in sys.argv:
290        sys.argv.remove('--debug')
291    else:
292        sys.argv.remove('-d')
293if debug >= 2:
294    cmdfile = open('freevo-gdb.sh', 'w')
295    print >>cmdfile,'#!/bin/bash'
296elif debug >= 1:
297    cmdfile = open('freevo-pdb.sh', 'w')
298    print >>cmdfile,'#!/bin/bash'
299
300freevo_script = os.path.abspath(sys.argv[0])
301if os.path.islink(freevo_script):
302    freevo_script = os.readlink(freevo_script)
303
304if os.path.isdir(os.path.join(os.path.dirname(freevo_script), 'src/plugins')):
305    #
306    # we start freevo from a directory
307    #
308    dname = os.path.dirname(freevo_script)
309    freevo_python  = os.path.join(dname, 'src')
310    freevo_helpers = os.path.join(dname, 'src/helpers')
311    freevo_locale  = os.path.join(dname, 'i18n')
312    freevo_share   = os.path.join(dname, 'share')
313    freevo_contrib = os.path.join(dname, 'contrib')
314    freevo_config  = os.path.join(dname, 'freevo_config.py')
315
316    if os.path.isfile(os.path.join(dname, 'runtime/runapp')):
317        #
318        # there is a runtime, use it
319        #
320        runapp = os.path.join(dname, './runtime/runapp')
321        python = [ runapp, os.path.join(dname, './runtime/apps/freevo_python') ]
322        preload = ''
323        f = open(os.path.join(dname, './runtime/preloads'))
324        for lib in f.readline()[:-1].split(' '):
325            preload += os.path.join(dname, lib) + ':'
326        if preload:
327            preload = preload[:-1]
328        os.environ['FREEVO_PRELOADS'] = preload
329        # FIXME: use FREEVO_PRELOADS in runapp to avoid chdirs
330
331    else:
332        #
333        # no runtime, get best python version
334        #
335        python = get_python(0)
336        if not python:
337            print 'Can\'t find python >= 2.4'
338            sys.exit(0)
339        python = [ python ]
340        runapp = ''
341else:
342    #
343    # installed version of freevo, get best python + freevo path
344    #
345    if not os.path.isfile(freevo_script):
346        for path in os.environ['PATH'].split(':'):
347            if os.path.isfile(os.path.join(path, freevo_script)):
348                freevo_script = os.path.join(path, freevo_script)
349    python, freevo_python = get_python(1)
350    if not python:
351        print 'can\'t find python version with installed freevo'
352        sys.exit(0)
353    freevo_helpers = os.path.join(freevo_python, 'helpers')
354    dname = os.path.abspath(os.path.join(os.path.dirname(freevo_script), '../'))
355    freevo_locale  = os.path.join(dname, 'share/locale')
356    freevo_share   = os.path.join(dname, 'share/freevo')
357    freevo_contrib = os.path.join(freevo_share, 'contrib')
358    freevo_config  = os.path.join(freevo_share, 'freevo_config.py')
359    runapp         = ''
360    python = [ python ]
361
362# add the variables from above into environ so Freevo can use them, too
363for var in ('runapp', 'freevo_script', 'freevo_python', 'freevo_locale',
364            'freevo_share', 'freevo_contrib', 'freevo_config', 'freevo_helpers'):
365    os.environ[var.upper()] = eval(var)
366    _debug_('%s=%r' % (var.upper(), os.environ[var.upper()]))
367    _gdb_script_('export %s=%s' % (var.upper(), os.environ[var.upper()]))
368
369# extend PYTHONPATH to freevo
370if os.environ.has_key('PYTHONPATH'):
371    os.environ['PYTHONPATH'] = '%s:%s' % (freevo_python, os.environ['PYTHONPATH'])
372else:
373    os.environ['PYTHONPATH'] = freevo_python
374_debug_('%s=%r' % ('PYTHONPATH', os.environ['PYTHONPATH']))
375_gdb_script_('export %s=%s' % ('PYTHONPATH', os.environ['PYTHONPATH']))
376
377
378# extend PATH to make sure the basics are there
379os.environ['PATH'] = '%s:/usr/bin:/bin:/usr/local/bin:' % os.environ['PATH'] + \
380                     '/usr/X11R6/bin/:/sbin:/usr/sbin'
381_debug_('%s=%r' % ('PATH', os.environ['PATH']))
382_gdb_script_('export %s=%s' % ('PATH', os.environ['PATH']))
383
384# set basic env variables
385if not os.environ.has_key('HOME') or not os.environ['HOME']:
386    os.environ['HOME'] = '/root'
387if not os.environ.has_key('USER') or not os.environ['USER']:
388    os.environ['USER'] = 'root'
389_debug_('%s=%r' % ('USER', os.environ['USER']))
390_debug_('%s=%r' % ('HOME', os.environ['HOME']))
391
392# now check what and how we should start freevo
393bg    = 0 # start in background
394proc  = [ os.path.abspath(os.path.join(freevo_python, 'main.py')) ]
395name  = os.path.splitext(os.path.basename(os.path.abspath(sys.argv[0])))[0]
396check = 1 # check running instance
397profile = 0
398
399if '--profile' in sys.argv or '-p' in sys.argv:
400    profile = 1
401    if '--profile' in sys.argv:
402        sys.argv.remove('--profile')
403    else:
404        sys.argv.remove('-p')
405
406if len(sys.argv) > 1:
407    arg = sys.argv[1]
408else:
409    arg = ''
410
411# check the args
412
413if arg in ('--help', '-h'):
414    # show help
415    show_help()
416
417if arg == 'stop':
418    # stop running freevo
419    if not stop(name, python + proc):
420        print 'freevo not running'
421    sys.exit(0)
422
423elif arg == 'start':
424    # start freevo in background
425    sys.argv = [ sys.argv[0] ]
426    bg = 1
427
428elif arg == '-fs':
429    # start X server and run freevo, ignore everything else for now
430    server_num = 0
431    while 1:
432        if not os.path.exists('/tmp/.X11-unix/X' + str(server_num)):
433            break
434        server_num += 1
435    sys.stdin.close()
436    os.execvp('xinit', [ 'xinit', freevo_script, '--force-fs',  '--', ':'+str(server_num) ] + sys.argv[2:])
437
438elif arg == 'execute':
439    # execute a python script
440    proc  = sys.argv[2:]
441    check = 0
442
443elif arg == 'setup':
444    # run setup
445    proc = [ os.path.join(freevo_python, 'setup_freevo.py') ] + sys.argv[2:]
446
447elif arg == 'prompt':
448    # only run python inside the freevo env
449    proc = []
450    profile = 0
451    check = 0
452
453elif arg == 'runapp':
454    # Oops, runapp. We don't start python, we start sys.argv[1]
455    # with the rest as args
456    python[-1] = sys.argv[2]
457    proc       = sys.argv[3:]
458    check      = 0
459
460elif arg and name == 'freevo' and not arg.startswith('-'):
461    # start a helper. arg is the name of the script in
462    # the helpers directory
463    name     = arg
464    proc     = [ os.path.join(freevo_python, 'helpers', name + '.py') ]
465    if len(sys.argv) > 2:
466        if sys.argv[2] == 'stop':
467            if not stop(name, python + proc):
468                print '%s not running' % name
469            sys.exit(0)
470        if sys.argv[2] == 'start':
471            bg = 1
472            sys.argv = [ sys.argv[0] ]
473        else:
474            sys.argv = [ sys.argv[0] ] + sys.argv[2:]
475
476elif arg and name == 'freevo' and not (arg in ['--force-fs', '--trace', '--doc']):
477    # ok, don't know about that arg, freevo should be started, but
478    # it's also no freevo arg
479    print 'unknown command line option: %s' % sys.argv[1:]
480    print
481    show_help()
482
483else:
484    # arg for freevo
485    proc += sys.argv[1:]
486
487
488if name != 'freevo':
489    proc = [ os.path.join(freevo_python, 'helpers', name + '.py') ] +  sys.argv[1:]
490    if not os.path.isfile(proc[0]):
491        if os.path.isfile(name):
492            name = os.path.splitext(os.path.basename(name))[0]
493            proc = proc[1:]
494        else:
495            proc = [ os.path.join(freevo_python, 'helpers', name + '.py') ] +  sys.argv[1:]
496            print 'can\'t find helper %s' % name
497            sys.exit(1)
498
499if check and getpid(name, python + proc)[1]:
500    if name != 'freevo':
501        print '%s still running, run \'freevo %s stop\' to stop' % (name, name)
502    else:
503        print 'freevo still running, run \'freevo stop\' to stop'
504    sys.exit(0)
505
506if profile:
507    if sys.hexversion > 0x02050000:
508        python += ['-m', 'cProfile', '-o', '/tmp/%s.stats' % name]
509    else:
510        python += ['-m', 'profile', '-o', '/tmp/%s.stats' % name]
511   
512start(name, python+proc, bg, check)
Note: See TracBrowser for help on using the browser.