~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/console.py

  • Committer: William Grant
  • Date: 2012-06-28 01:52:02 UTC
  • Revision ID: me@williamgrant.id.au-20120628015202-f6ru7o367gt6nvgz
Hah

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
import errno
25
25
import cPickle
26
 
import md5
 
26
import hashlib
27
27
import os
28
28
import random
29
29
import socket
30
30
import StringIO
31
31
import uuid
32
32
 
33
 
import cjson
34
 
 
35
 
import ivle.conf
36
 
from ivle import (chat, util)
37
 
 
38
 
# Outside Jail
39
 
trampoline_path = os.path.join(ivle.conf.lib_path, "trampoline")
40
 
# Inside Jail
41
 
python_path = "/usr/bin/python"
42
 
console_dir = os.path.join(ivle.conf.share_path, 'services')
43
 
console_path = os.path.join(console_dir, 'python-console')
 
33
from ivle import chat, interpret
44
34
 
45
35
class ConsoleError(Exception):
46
36
    """ The console failed in some way. This is bad. """
47
 
    def __init__(self, value):
48
 
        self.value = value
49
 
    def __str__(self):
50
 
        return repr(self.value)
 
37
    pass
51
38
 
52
39
class ConsoleException(Exception):
53
40
    """ The code being exectuted on the console returned an exception. 
54
41
    """
55
 
    def __init__(self, value):
56
 
        self.value = value
57
 
    def __str__(self):
58
 
        return repr(self.value)
 
42
    pass
59
43
 
60
44
class TruncateStringIO(StringIO.StringIO):
61
45
    """ A class that wraps around StringIO and truncates the buffer when the 
122
106
class Console(object):
123
107
    """ Provides a nice python interface to the console
124
108
    """
125
 
    def __init__(self, uid, jail_path, working_dir):
 
109
    def __init__(self, config, user, jail_path, working_dir):
126
110
        """Starts up a console service for user uid, inside chroot jail 
127
111
        jail_path with work directory of working_dir
128
112
        """
129
113
        super(Console, self).__init__()
130
114
 
131
 
        self.uid = uid
 
115
        self.config = config
 
116
        self.user = user
132
117
        self.jail_path = jail_path
133
118
        self.working_dir = working_dir
134
119
 
154
139
 
155
140
        # Create magic
156
141
        # TODO
157
 
        self.magic = md5.new(uuid.uuid4().bytes).digest().encode('hex')
 
142
        self.magic = hashlib.md5(uuid.uuid4().bytes).hexdigest()
158
143
 
159
144
        # Try to find a free port on the server.
160
145
        # Just try some random ports in the range [3000,8000)
165
150
        # is (k / N) ** t (e.g. 3.2*10e-9).
166
151
 
167
152
        tries = 0
 
153
        error = None
168
154
        while tries < 5:
169
155
            self.port = int(random.uniform(3000, 8000))
170
156
 
171
 
            # Start the console server (port, magic)
172
 
            # trampoline usage: tramp uid jail_dir working_dir script_path args
173
 
            # console usage:    python-console port magic
174
 
            res = os.spawnv(os.P_WAIT, trampoline_path, [
175
 
                trampoline_path,
176
 
                str(self.uid),
177
 
                ivle.conf.jail_base,
178
 
                ivle.conf.jail_src_base,
179
 
                ivle.conf.jail_system,
180
 
                self.jail_path,
181
 
                console_dir,
182
 
                python_path,
183
 
                console_path,
184
 
                str(self.port),
185
 
                str(self.magic),
186
 
                self.working_dir
187
 
                ])
 
157
            python_console = os.path.join(self.config['paths']['share'],
 
158
                        'services/python-console')
 
159
            args = [python_console, str(self.port), str(self.magic)]
188
160
 
189
 
            if res == 0:
 
161
            try:
 
162
                interpret.execute_raw(self.config, self.user, self.jail_path,
 
163
                        self.working_dir, "/usr/bin/python", args)
190
164
                # success
191
 
                break;
192
 
 
193
 
            tries += 1
194
 
 
195
 
        # If we can't start the console after 5 attemps (can't find a free port 
196
 
        # during random probing, syntax errors, segfaults) throw an exception.
 
165
                break
 
166
            except interpret.ExecutionError, e:
 
167
                tries += 1
 
168
                error = e.message
 
169
 
 
170
        # If we can't start the console after 5 attemps (can't find a free 
 
171
        # port during random probing, syntax errors, segfaults) throw an 
 
172
        # exception.
197
173
        if tries == 5:
198
 
            raise ConsoleError("Unable to start console service!")
 
174
            raise ConsoleError('Unable to start console service: %s'%error)
199
175
 
200
176
    def __chat(self, cmd, args):
201
177
        """ A wrapper around chat.chat to comunicate directly with the 
212
188
            else:
213
189
                # Some other error - probably serious
214
190
                raise socket.error, (enumber, estring)
215
 
        except cjson.DecodeError:
 
191
        except ValueError:
216
192
            # Couldn't decode the JSON
217
193
            raise ConsoleError(
218
194
                "Could not understand the python console response")
 
195
        except chat.ProtocolError, e:
 
196
            raise ConsoleError(*e.args)
219
197
 
220
198
        return response
221
199
 
269
247
 
270
248
        # Unpickle the globals
271
249
        for g in globals['globals']:
272
 
            globals['globals'][g] = cPickle.loads(globals['globals'][g])
 
250
            globals['globals'][g] = cPickle.loads(str(globals['globals'][g]))
273
251
 
274
252
        return globals['globals']
275
253
        
288
266
        # Unpickle any exceptions
289
267
        if 'exception' in call:
290
268
            call['exception']['except'] = \
291
 
                cPickle.loads(call['exception']['except'])
 
269
                cPickle.loads(str(call['exception']['except']))
292
270
 
293
271
        return call
294
272
 
300
278
              
301
279
        # Unpickle any exceptions
302
280
        if 'exception' in execute:
303
 
            return cPickle.loads(execute['exception'])
304
 
        else:
305
 
            return execute
 
281
            execute['exception'] = cPickle.loads(str(execute['exception']))
 
282
        return execute
306
283
 
307
284
 
308
285
    def set_vars(self, variables):